我理解(某种程度上)单子,并且理解运算符<-将从单子中提取值。
但是它如何与不同类型一起使用?
通常,我已经看到它被用来从IO monad中提取字符串。但是在下面的示例代码中,无法看到为什么它在主第三行中失败,抱怨说它期望使用IO int类型?编译器如何推断需要IO int?
它(<-
)在multWithLog
方法中又做什么?
import Control.Monad.Trans.Writer.Lazy
main = do
putStrLn $ show $ logNumber 3 -- prints WriterT (Identity (3,["Got Number: 3"]))
putStrLn $ show $ multWithLog -- prints WriterT (Identity (3,["Got Number: 3"]))
_ <- logNumber 3 -- fails with Couldn't match type ‘WriterT [String] Data.Functor.Identity.Identity’ with ‘IO’
-- Expected type: IO Int
-- Actual type: Writer [String] Int
putStrLn "test"
logNumber :: Int -> Writer [String] Int
logNumber x = writer (x, ["Got Number: " ++ show x])
multWithLog :: Writer [String] Int
multWithLog = do
a <- logNumber 3
--b <- logNumber 5
return a
答案 0 :(得分:6)
do
块中的每个语句都必须具有相同的单子类型。
在
multWithLog = do
a <- logNumber 3
return a
我们有logNumber 3 :: Writer [String] Int
和return a :: (Monad m) => m Int
(是多态的),因此整个类型的类型检查都为Writer [String] Int
(带有m = Writer [String]
,它是单子)。
在
main = do
putStrLn $ show $ logNumber 3
putStrLn $ show $ multWithLog
_ <- logNumber 3
putStrLn "test"
我们有putStrLn ... :: IO ()
和logNumber 3 :: Writer [String] Int
。这是类型错误,因为Writer [String]
与IO
不同。
根本原因是do
块只是调用>>=
和>>
的语法糖。例如。您的main
确实意味着
main =
(putStrLn $ show $ logNumber 3) >>
(putStrLn $ show $ multWithLog) >>
logNumber 3 >>= \_ ->
putStrLn "test"
使用
(>>) :: (Monad m) => m a -> m b -> m b
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
这要求类型m
始终保持不变。
答案 1 :(得分:3)
注意诸如此类的措辞
从monad中提取值
一个monad不包含'a'值。例如,Maybe
包含零或一个值。列表([]
)包含多个值。有关更多详细信息,请参见this answer。
例如,在列表情况下,<-
运算符一次提取列表值的每个,一次。
使用do
表示法时,提取的所有值必须属于相同的Monad
。在OP中,由于Monad
返回IO
的值,因此编译器推断所讨论的putStrLn
是IO ()
。
logNumber
返回Writer [String] Int
值,尽管这也是一个Monad
实例,但它与IO
不同。因此,该代码不会键入check。
答案 2 :(得分:1)
保持简单。这是两个事实
Writer [String]
实际上是单子,因此Writer [String] Int
可以看作m Int
do
块中的每个动作都应在同一monad中发生。在main
函数中,编译器的推理如下:
IO
的类型为putStrLn ...
,我在IO ()
monad中工作_ <- logNumber 3
。由于我在IO
单子目录中,因此logNumber 3
应该是IO WhatEver
logNumber 3
实际上是m Int
类型的单子数值m
是Writer [String]
单子,而不是IO
单子Writer [String] Int
不正确,应为IO Int
这就是IO Int
的来源。我只是想在这里进行教学。查看@melpomene的答案以获取完整说明
希望有帮助。