为什么“fmap(replicate 3)Just”有一种“a - > [Maybe a]”,在Haskell中

时间:2014-06-03 02:10:39

标签: haskell types functor

最近我正在使用Learn You a Haskell for Great Good在线学习Haskell。

我有两个问题:

  1. fmap (replicate 3)的类型为Functor f=> f a -> f [a]。为什么可以将其应用于Just

  2. 此外,为什么fmap (replicate 3) Just类型a -> [Maybe a]而不是a -> Maybe [a]类型?

2 个答案:

答案 0 :(得分:13)

如果您意识到fmap结束的是功能而不是Maybe a值,这很容易理解。 Just的类型为a -> Maybe a,因此它属于(->) a仿函数,而不是Maybe仿函数。函数Functor的实例看起来像

instance Functor ((->) a) where
    fmap g f = g . f

所以fmap只是成为正常的功能组合!这意味着

fmap (replicate 3) Just

相同
replicate 3 . Just

非常清楚地具有类型a -> [Maybe a]


更多"类型代数"解释是排列类型和替代,直到你不能再。让我们从我们的类型开始,但使用不同的变量名称,以便更容易理解:

fmap      :: Functor f => (a -> b) -> (f a -> f b)
replicate :: Int -> c -> [c]
Just      :: x -> Maybe x

然后是fmap (replicate 3)

     (replicate 3) :: c -> [c]
fmap               :: (a -> b) -> (f a -> f b)

所以

(c -> [c]) ~ (a -> b)

暗示

c   ~ a
[c] ~ b
b   ~ [a]

所以替换回来:

fmap (replicate 3) :: f c -> f [c]

那么我们fmap的结果是Just,其类型为

Just :: x -> Maybe x

可以在前缀格式中重写为

Just :: (->) x (Maybe x)

或者如果我们真的想要更多括号

Just :: ((->) x) (Maybe x)

然后

                   Just :: ((->) x) (Maybe x)
fmap (replicate 3)      :: f        c         -> f [c]

暗示

((->) x) (Maybe x) ~ f c
(->) x  ~ f
Maybe x ~ c
[c] ~ [Maybe x]

所以替换回来:

fmap (replicate 3) :: ((->) x) (Maybe x) -> ((->) x) [Maybe x]

回到中缀符号

fmap (replicate 3) :: (x -> Maybe x) -> (x -> [Maybe x])

然后应用Just

fmap (replicate 3) Just :: x -> [Maybe x]

我想在此强调,MaybeFunctor与此减少无关,唯一涉及的Functor是函数Functor。列表也是Functor,但仅仅因为它出现在replicate类型中并不意味着在这种情况下它很重要。很容易与函数混淆

fmap (replicate 3) . Just :: a -> Maybe [a]

但由于添加了.,这完全不同。

答案 1 :(得分:4)

Functor正在使用的fmap实例是(->) r,而不是Maybe。让我们来看看类型:

replicate 3        :: a -> [a]
fmap (replicate 3) :: Functor f => f a -> f [a]
Just               :: b -> Maybe b
  1. 在表达式fmap (replicate 3) Just中,我们需要将Functor f => f a部分与b -> Maybe b匹配。这选择的实例是(->) r实例(因为Just是一个函数),我们最终得到((->) r a) -> ((->) r [a])
  2. 我们可以扩展这些(->)应用程序以获取此类型(专门将函数作为其参数):(r -> a) -> (r -> [a])
  3. 接下来,为了匹配Just的类型,我们需要将rbaMaybe b匹配(以便我们可以将(r -> a)(b -> Maybe b)匹配)给我们(b -> Maybe b) -> (b -> [Maybe b])
  4. 这是fmap (replicate 3)的专用类型,我们现在可以将Just应用于fmap (replicate 3) Just :: b -> [Maybe b],与a -> [Maybe a]相同。
  5. 作为旁注,fmap实例专用的完整类型(->) rfmap :: (a -> b) -> (r -> a) -> (r -> b),这意味着它与函数组合相同:fmap = (.)