我们知道Maybe 的种类是*->*。
所以它可能是Functor的一个实例
instance Functor Maybe where
fmap :: f -> Maybe a -> Maybe b
fmap f Nothing = Nothing
fmap f (Maybe x) = Maybe (f x)
第一个例子:
{-# LANGUAGE TypeSynonymInstances #-}
type MaybeAlias a = Maybe
instance {-# OVERLAPPING #-} Functor (MaybeAlias Int) where
fmap f functor = undefined
在TypeSynonymInstances扩展的作用下(几乎就像一个字符串替换),它等于
instance {-# OVERLAPPING #-} Functor Maybe where
fmap f functor = undefined
没关系,因为allow fully applied type synonyms to be used in instance heads
见另一个例子:
{-# LANGUAGE TypeSynonymInstances #-}
type MaybeAlias a b = Maybe
MaybeAlias Int 现在是什么样的?好心人是*->*->*。
为什么?
正如上面的@heatsink 评论:
部分应用的同义词实际上是一个函数,其输入是未应用的类型,其输出是一个类型
现在解释一下:
在type MaybeAlias a b = Maybe的定义下:
MaybeAlias 就像一个部分应用的函数:
(MaybeAlias) :: a -> b -> Maybe
MaybeAlias Int 就像一个部分应用的函数:
(MaybeAlias Int) :: b -> Maybe
Maybe 的种类是 * -> *,b 的种类是 *。
所以MaybeAlias Int 的种类是* -> (* -> *)。
而* -> (* -> *) 等于* -> * -> *。
下面代码不起作用的根本原因,因为Functor typeclass 只接受类型为* -> *,而不是* -> * ->*!
{-# LANGUAGE TypeSynonymInstances #-}
type MaybeAlias a b = Maybe
instance {-# OVERLAPPING #-} Functor (MaybeAlias Int) where
fmap f functor = undefined
为什么下面的代码不起作用?
class Example e where
thingy :: a -> b -> e a b
-- legit, but awkward
newtype FuncWrapper e a b = FuncWrapper { ap :: a -> e a b }
instance (Example e) => Example (FuncWrapper e) where
thingy _ = FuncWrapper . flip thingy
funcWrapperUse :: (Example e) => e Int String
funcWrapperUse = thingy 1 "two" `ap` 3 `ap` 4 `ap` 5
-- not legal, but a little easier to use
type FuncSynonym e a b = a -> e a b
instance (Example e) => Example (FuncSynonym e) where
thingy _ = flip thingy
funcSynonymUse :: (Example e) => e Int String
funcSynonymUse = thingy 1 "two" 3 4 5
Example typeclass 接受具有* -> * -> * 类型的类型
FuncSynonym 就像一个部分应用的函数:
FuncSynonym :: e -> a -> b -> (a -> e a b)
FuncSynonym e 就像一个部分应用的函数:
(FuncSynonym e):: a -> b -> ( a -> e a b)
a 的种类是*,
b 的种类是*,
a -> e a b 的那种*
(FuncSynonym e)的种类是* -> * -> *
Example typeclass 接受具有 kind * -> * -> * 的类型,但为什么仍然不起作用?
这是ghc issue 785和comment中的另一个原因