我已尝试在前奏中使用以下代码段:
*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]
为什么我没有空列表?
答案 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中,默认Monad
为IO
,因此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 m
到IO
,因此在提示时它的类型为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]