仿函数 f 是一个类型构造函数,它有一个关联函数 fmap,它从 (a -> b) 类型的函数创建一个 (f a) -> (f b) 类型的函数并应用它 "在里面”:(括号是多余的,仅用于清晰/强调)
fmap :: (Functor f) => ( a -> b)
-> (f a) -> (f b)
-- i.e. g :: a -> b -- from this
-- --------------------------
-- fmap g :: (f a) -> (f b) -- we get this
(从 a 到 b 的 g 中读取“fmap”从 f a 到 f b")。
换句话说,“函子”意味着它可以替代f in
fmap id (x :: f a) = x
(fmap g . fmap h) = fmap (g . h)
这样所涉及的表达式才有意义(即格式正确,即具有类型),而且,重要的是, 上述等式成立——它们实际上是两个 “函子法律”。
你有
data LiftItOut h a = MkLiftItOut (h a) -- "Mk..." for "Make..."
------------- ----------- ------
new type, data type of the data constructor's
defined here constructor one argument (one field)
这意味着h a 是一种事物,可以作为MkLiftItOut 的参数。比如Maybe Int(即h ~ Maybe和a ~ Int)、[(Float,String)](即h ~ []和a ~ (Float,String))等
h、a 是类型变量——意思是,它们可以被任何特定类型替换,这样整个语法表达式才有意义。
这些句法表达式包括MkLiftItOut x,它是LiftItOut h a 类型的事物,前提是x 是h a 类型的事物; LiftItOut h a 是一个类型; h a 是一种事物,可以作为 MkLiftItOut 的参数出现。因此我们可以在我们的程序中拥有
v1 = MkLiftItOut ([1,2,3] :: [] Int ) :: LiftItOut [] Int
v2 = MkLiftItOut ((Just "") :: Maybe String) :: LiftItOut Maybe String
v3 = MkLiftItOut (Nothing :: Maybe () ) :: LiftItOut Maybe ()
.....
等等。然后我们有
ghci> :i Functor
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
..........
这意味着Functor f => (f a)是一种变量可以引用的事物类型,例如
-- f a
v4 = Just 4 :: Maybe Int
v41 = 4 :: Int
v5 = [4.4, 5.5] :: [] Float
v51 = 4.4 :: Float
v52 = 5.5 :: Float
v6 = (1,"a") :: ((,) Int) String -- or simpler, `(Int, String)`
v61 = "a" :: String
v7 = (\x -> 7) :: ((->) Int) Int -- or simpler, `Int -> Int`
这里a是一个事物的类型,f a是一个事物的类型,f是一个类型,当给定一个事物的类型时,它就变成了一个事物的类型;等等。没有任何东西可以被单独具有 f 类型的变量引用。
以上所有fs 都是Functor 类型类的实例。这意味着在图书馆的某处有定义
instance Functor Maybe where ....
instance Functor [] where ....
instance Functor ((,) a) where ....
instance Functor ((->) r) where ....
请注意,我们总是有 f 和 a。 f 尤其可以由多个组成部分组成,但 a 始终是某个一个类型。
因此在这种情况下我们必须有
instance Functor (LiftItOut h) where ....
(...为什么? 一定要说服自己;看看上述所有陈述如何适用和正确)
那么实际定义一定是
-- fmap :: (a -> b) -> f a -> f b
-- fmap :: (a -> b) -> LiftItOut h a -> LiftItOut h b
fmap g (MkLiftItOut x ) = (MkLiftItOut y )
where
y = ....
特别是,我们将有
-- g :: a -> b -- x :: (h a) -- y :: (h b)
我们甚至不知道h 是什么。
我们如何解决这个问题?当我们对 h、a 和 b 都不了解的情况下,我们如何从 h a 类型的事物构造 h b 类型的事物?
我们不能。
但是如果我们知道h 也是Functor 呢?
instance (Functor h) => Functor (LiftItOut h) where
-- fmap :: (a -> b) -> (f a) -> (f b)
-- fmap :: (a -> b) -> (LiftItOut h a) -> (LiftItOut h b)
fmap g (MkLiftItOut x ) = (MkLiftItOut y )
where
-- fmap :: (a -> b) -> (h a) -> (h b)
y = ....
希望你能完成这件事。并且也在你的问题中做其他类型。如果没有,请针对 one 类型发布一个新问题,您可能会遇到任何其他问题。