为什么它必须是monad?

时间:2017-08-10 08:47:36

标签: haskell

我已尝试在前奏中使用以下代码段:

*ExerciseMonad Control.Monad> :t fmap ((:) 3) []

结果为空[]

然后我将空列表转换为monad结构:

*ExerciseMonad Control.Monad> x = return []
*ExerciseMonad Control.Monad> :t x
x :: Monad m => m [t]

返回的值包含在Monad结构中。

这似乎是一种魔力,我没有得到一个空列表:

*ExerciseMonad Control.Monad> fmap ((:) 3) x
[3]

为什么我没有空列表?

3 个答案:

答案 0 :(得分:8)

fmap适用于任何Functor,包括[]。请注意GHCi如何推断您的第一个表达式的类型:

Prelude> :t fmap ((:) 3) []
fmap ((:) 3) [] :: Num a => [[a]]

返回类型是嵌套列表,因为否则cons运算符(:)没有意义。但是,当您fmap在空列表([])上时,无事可做,因此结果也是空列表。

另一方面,第二个表达式的类型不同:

Prelude> x = return []
Prelude> :t x
x :: Monad m => m [t]
Prelude> :t fmap ((:) 3) x
fmap ((:) 3) x :: (Num a, Monad f) => f [a]

您会注意到返回值不再是嵌套列表,而是Monad超过[a]。但是,Monad包含Applicative,其中又包含Functor,因此在第二个表达式中,fmap不再是[]实例,而是f。正如李指出的那样,在GHCi中,默认MonadIO,因此fmap中的fmap ((:) 3) x映射IO,而不是[]。< / p>

这意味着x实际上在GHCi中变为IO [],而fmap monad中的IO将映射函数应用于monad中包含的数据({{ 1}})。这意味着您获得[],即((:) 3) []

[3]

答案 1 :(得分:2)

在您的第一个示例中,fmap ((:) 3) []的类型为Num a => [[a]]fmap f [] == []

相比之下,fmap ((:) 3) x的类型为(Monad m, Num a) => m [a]GHCi deafults mIO,因此在提示时它的类型为Num a => IO [a]。将评估相应的IO操作,如果它是Show的实例,则打印结果。 a默认为Integer[Integer]Show个实例,因此会显示。

答案 2 :(得分:1)

fmap ((:) 3) []

实际上会将(:) 3运算符应用于列表仿函数的“内容”。由于您没有内容,通常会得到一个空列表作为回报。如果你喜欢它的话;

fmap ((:) 3) [[],[],[]]

然后你会得到[[3],[3],[3]]作为返回值。

现在,如果您选择向fmap提供列表值。您可以将列表值“包装”到List值构造函数中,例如;

*Main> fmap ((:) 3) $ return []
[3]