[英]How does the operator <- in haskell behave?
I understand (somewhat) monads and understand that the operator <- will extract the value from the monad. 我了解(某种程度上)单子,并且理解运算符<-将从单子中提取值。
But how does it work with different types? 但是它如何与不同类型一起使用?
Typically, I have seen it being used to extract strings from IO monad. 通常,我已经看到它用于从IO monad提取字符串。 But in the example code below am not able to see why it fails in main 3rd line, complaining that it is expecting a type of IO int? 但是在下面的示例代码中,无法看到为什么它在主第三行中失败,抱怨说它期望使用IO int类型? How is the compiler infering that an IO int is needed? 编译器如何推断需要IO int?
Also what does it ( <-
) do in the multWithLog
method? 另外,在multWithLog
方法中( <-
)有什么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
Every statement in a do
block must be from the same monadic type. do
块中的每个语句do
必须来自同一单子类型。
In 在
multWithLog = do
a <- logNumber 3
return a
we have logNumber 3 :: Writer [String] Int
and return a :: (Monad m) => m Int
(which is polymorphic), so the whole thing typechecks as Writer [String] Int
(with m = Writer [String]
, which is a monad). 我们有logNumber 3 :: Writer [String] Int
并return a :: (Monad m) => m Int
(它是多态的),因此整个类型都作为Writer [String] Int
(其中m = Writer [String]
,这是一个单子)。
In 在
main = do
putStrLn $ show $ logNumber 3
putStrLn $ show $ multWithLog
_ <- logNumber 3
putStrLn "test"
we have putStrLn ... :: IO ()
and logNumber 3 :: Writer [String] Int
. 我们有putStrLn ... :: IO ()
和logNumber 3 :: Writer [String] Int
。 This is a type error because Writer [String]
is not the same as IO
. 这是类型错误,因为Writer [String]
与IO
。
The underlying reason is that do
blocks are just syntactic sugar for calls to >>=
and >>
. 根本原因是do
块只是>>=
和>>
调用的语法糖。 Eg your main
really means 例如,您的main
意思是
main =
(putStrLn $ show $ logNumber 3) >>
(putStrLn $ show $ multWithLog) >>
logNumber 3 >>= \_ ->
putStrLn "test"
with 与
(>>) :: (Monad m) => m a -> m b -> m b
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
which requires the type m
to remain the same throughout. 这要求类型m
始终保持相同。
Be careful with wording such as 注意诸如以下的措辞
extract the value from the monad 从monad提取值
A monad doesn't contain 'a' value. 单声道不包含“ a”值。 For example, Maybe
contains zero or one value. 例如, Maybe
包含零或一个值。 List ( []
) contains multiple values. 列表( []
)包含多个值。 See this answer for more details. 有关更多详细信息,请参见此答案 。
In the list case, for example, the <-
operator extracts each of the list values, one at a time. 例如,在列表的情况下, <-
运算符一次提取一个列表值。
When you use do
notation, all values extracted must belong to the same Monad
. 使用do
表示法时,提取的所有值必须属于同一Monad
。 In the OP, the compiler infers that the Monad
in question is IO
, since putStrLn
returns IO ()
values. 在OP中,由于putStrLn
返回IO ()
值,因此编译器推断出该Monad
为IO
。
logNumber
, on the other hand, returns Writer [String] Int
values, and while that's also a Monad
instance, it's not the same as IO
. 另一方面, logNumber
返回Writer [String] Int
值,尽管这也是Monad
实例,但它与IO
。 Therefore, the code doesn't type check. 因此,该代码不会键入检查。
Kepping things simple. 简化事情。 These are two facts 这是两个事实
Writer [String]
is actually monad, so Writer [String] Int
can be seen as m Int
Writer [String]
实际上是monad,因此Writer [String] Int
可以看作是m Int
do
block should happen within the same monad. do
块中的每个动作都应在同一monad中发生。 In the main
function the compiler is reasoning as follows: 在main
函数中,编译器的推理如下:
IO
monad since putStrLn ...
is of type IO ()
我在IO
monad中工作,因为putStrLn ...
是IO ()
类型 _ <- logNumber 3
. 让我计算_ <- logNumber 3
。 Since I am in the IO
monad, logNumber 3
should be IO WhatEver
由于我在IO
monad中,因此logNumber 3
应该是IO WhatEver
logNumber 3
is actually a monadic value of type m Int
logNumber 3
实际上是类型m Int
的单子值 m
is the Writer [String]
monad, not the IO
monad m
是Writer [String]
monad,而不是IO
monad Writer [String] Int
is incorrect an It should be IO Int
打印一条错误消息,指出Writer [String] Int
不正确,应为IO Int
So that is where IO Int
comes from. 这就是IO Int
来源。 I am just triying to be pedagogic here. 我只是想在这里进行教学。 Check @melpomene's answer for a complete explanation 查看@melpomene的答案以获取完整说明
Hope it helps. 希望能帮助到你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.