简体   繁体   English

haskell中的运算符<-表现如何?

[英]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] Intreturn 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 ()值,因此编译器推断出该MonadIO

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 这是两个事实

  1. Writer [String] is actually monad, so Writer [String] Int can be seen as m Int Writer [String]实际上是monad,因此Writer [String] Int可以看作是m Int
  2. Every action in a do block should happen within the same monad. do块中的每个动作都应在同一monad中发生。

In the main function the compiler is reasoning as follows: main函数中,编译器的推理如下:

  1. I am working within the IO monad since putStrLn ... is of type IO () 我在IO monad中工作,因为putStrLn ...IO ()类型
  2. Let me compute _ <- logNumber 3 . 让我计算_ <- logNumber 3 Since I am in the IO monad, logNumber 3 should be IO WhatEver 由于我在IO monad中,因此logNumber 3应该是IO WhatEver
  3. logNumber 3 is actually a monadic value of type m Int logNumber 3实际上是类型m Int的单子值
  4. Wait! 等待! m is the Writer [String] monad, not the IO monad mWriter [String] monad,而不是IO monad
  5. Print an error saying that 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM