在 Haskell 中,几乎总是可以推导出函子(functor),但是否存在这样的情况:某个类型既满足函子定律(例如
那么对于 Foldable、Traversable、Semigroup 等类型呢?是否存在非平凡的情况?
fmap id == id
),又不能按照简单的规则进行推导?那么对于 Foldable、Traversable、Semigroup 等类型呢?是否存在非平凡的情况?
fmap id == id
),又不能按照简单的规则进行推导?我刚刚发现了一个有趣的论点。 (由于太晚了,明天可能会更加清晰)
我们可以构建一个GADT类型来证明SK可简化性:
infixl 9 :%:
data Term = S | K | Term :%: Term
-- small step, you can get from t to t' in one step
data Red1 t t' where
Red1S :: Red1 (S :%: x :%: y :%: z) (x :%: z :%: (y :%: z))
...
data Red t a where
RedStep :: Red1 t t' -> Red t' a -> Red t a
RedK :: a -> Red K a
RedS :: (a -> Bool) -> Red S a
Red1
中选择确定性规约策略,请定义data Blue t where BlueStep :: Red1 t t' -> Blue t' -> Blue t
。(对于非确定性策略,情况会变得有点丑陋,因为您必须分离所有重叠的规则)。现在,您可以在Blue t
旁边消耗Red t a
。在每个步骤中,Blue t
中的Red1 t t'
证明t
不是S
。 - dfeuert
不等于S
,但为了证明函子性质,我们需要在每一个步骤中都满足这一条件。 - luqui明确的空参数类型可以自动转换为函子:
data T a deriving Functor
import Data.Void
data T a = K a (a -> Void)
deriving Functor -- fails
{-
error:
• Can't make a derived instance of ‘Functor T’:
Constructor ‘K’ must not use the type variable in a function argument
• In the data declaration for ‘T’
-}
instance Functor T where
fmap f (K x y) = absurd (y x)
这可能是一个合法的实例。
有人可能会争论,通过利用底部(bottoms),可以找到上述实例中函子定律的反例。但在这种情况下,我想知道即使存在底部,所有“标准”的函子实例是否实际上都是合法的。(也许它们是合法的?)
data Foo a = Foo (a -> Bool) !Void
。还有一种逆变性可能会阻碍它的方法:newtype Bar f a = Bar (f a -> Bool)
。 GHC 无法派生完全有效的实例
instance Contravariant f => Functor (Bar f) where fmap f (Bar g) = Bar (g . contramap f)
。主要问题在于将“Contravariant”添加到派生混合中会导致出现多个潜在实例(具有不兼容限制),例如 newtype Baz f g a = Baz (f (g a))
。 - dfeuerdata A a where
A1 :: (Ord a) => a -> A a
deriving instance Functor A -- doesn't work
实际上,如果我们手动编写,它也不起作用。
instance Functor A where
fmap f (A1 a) = A1 (f a) -- Can't deduce Ord for f a
class C c
instance C c
C
代替Ord
进行操作。data B b where
B1 :: (C b) => b -> B b
deriving instance Functor B -- doesn't work
instance Functor B where
fmap f (B1 b) = B1 (f b) -- does work!
在base
中有一个标准类型,叫做Compose
,定义如下:
newtype Compose f g a = Compose { getCompose :: f (g a) }
Functor
实例是这样实现的:instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose v) = Compose (fmap (fmap f) v)
instance (Contravariant f, Contravariant g) => Functor (Compose f g) where
fmap f (Compose v) = Compose (contramap (contramap f) v)
Compose
有两个不同的实例可用,这表明没有一组规则可以自动适用于涵盖所有可能情况。f
和g
都具有幻影参数时),实例具有相同的行为。因此,我认为这与不兼容的约束条件有关,而不是不同的行为。 - dfeuer