将“do”转换为“do”具有两个以上操作的符号来使用绑定函数

发布于 2024-09-18 23:29:10 字数 291 浏览 2 评论 0原文

我知道以下“do”符号的“bind”功能相当于 getLine >>= \line -> putStrLn

do line <- getLine
   putStrLn line

但是下面的符号如何等同于bind函数呢?

do line1 <- getLine
   putStrLn "enter second line"
   line2 <- getLine
   return (line1,line2)

I know that the following "do" notation's "bind" function is equivalent to getLine >>= \line -> putStrLn

do line <- getLine
   putStrLn line

But how is the following notation equivalent to bind function?

do line1 <- getLine
   putStrLn "enter second line"
   line2 <- getLine
   return (line1,line2)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

风蛊 2024-09-25 23:29:10

我认为您正在尝试查看如何绑定“putStrLn”的结果。答案就在 putStrLn 的类型中:

putStrLn :: String -> IO ()

记住“()”是单位类型,它具有单个值(也写为“()”)。所以你可以用完全相同的方式绑定它。但由于您不使用它,因此将其绑定到“不关心”值:

getLine >>= \line1 ->
putStrLn "enter second line" >>= \_ ->
getline >>= \line2 ->
return (line1, line2)

碰巧,已经定义了一个用于忽略返回值的运算符“>>”。所以你可以重写这个,因为

getLine >>= \line1 ->
putStrLn "enter second line" >>
getline >>= \line2 ->
return (line1, line2)

我不确定你是否也在尝试理解绑定运算符是如何以菊花链方式连接的。为了看到这一点,让我在上面的示例中添加隐式括号和额外的缩进:

getLine >>= (\line1 ->
   putStrLn "enter second line" >> (
      getline >>= (\line2 ->
         return (line1, line2))))

每个绑定运算符将左侧的值与右侧的函数链接起来。该函数由“do”子句中的所有其余行组成。因此,通过 lambda 绑定的变量(第一行中的“line1”)在该子句的整个其余部分的范围内。

I take it you are trying to see how to bind the result of "putStrLn". The answer is in the type of putStrLn:

putStrLn :: String -> IO ()

Remember that "()" is the unit type, which has a single value (also written "()"). So you can bind this in exactly the same way. But since you don't use it you bind it to a "don't care" value:

getLine >>= \line1 ->
putStrLn "enter second line" >>= \_ ->
getline >>= \line2 ->
return (line1, line2)

As it happens, there is an operator already defined for ignoring the return value, ">>". So you could just rewrite this as

getLine >>= \line1 ->
putStrLn "enter second line" >>
getline >>= \line2 ->
return (line1, line2)

I'm not sure if you are also trying to understand how bind operators are daisy-chained. To see this, let me put the implicit brackets and extra indentation in the example above:

getLine >>= (\line1 ->
   putStrLn "enter second line" >> (
      getline >>= (\line2 ->
         return (line1, line2))))

Each bind operator links the value to the left with a function to the right. That function consists of all the rest of the lines in the "do" clause. So the variable being bound through the lambda ("line1" in the first line) is in scope for the whole of the rest of the clause.

寄离 2024-09-25 23:29:10

对于这个特定的示例,您实际上可以通过使用 Control.Applicative 中的组合器来避免 do>>=

module Main where
import Control.Applicative ((<
gt;), (<*>), (<*))

getInput :: IO (String, String)
getInput = (,) <
gt; getLine <* putStrLn "enter second line" <*> getLine

main = print =<< getInput

它按预期工作:

travis@sidmouth% ./Main
hello
enter second line
world
("hello","world")

一开始看起来有点奇怪,但在我看来,一旦你习惯了,应用风格就会感觉非常自然。

For this specific example you can actually avoid both do and >>= by using combinators from Control.Applicative:

module Main where
import Control.Applicative ((<
gt;), (<*>), (<*))

getInput :: IO (String, String)
getInput = (,) <
gt; getLine <* putStrLn "enter second line" <*> getLine

main = print =<< getInput

Which works as expected:

travis@sidmouth% ./Main
hello
enter second line
world
("hello","world")

It looks a little weird at first, but in my opinion the applicative style feels very natural once you're used to it.

伏妖词 2024-09-25 23:29:10

我强烈建议您阅读脱糖一章Real-World haskell 书中的 Do-blocks。它告诉你,你们都错了。对于程序员来说,这是使用 lambda 的自然方式,但是 do-block 是使用函数实现的,如果发生模式处理失败,将调用相应 monad 的 fail 实现。

例如,您的情况是这样的:

let f x =
        putStrLn "enter second line" >>
        let g y = return (x,y)
            g _ = fail "Pattern mismatched"
        in getLine >>= g
    f _ = fail "Pattern mismatched"
in getLine >>= f

在这样的情况下,这可能完全无关紧要。但考虑一些涉及模式匹配的表达式。另外,您可以将此效果用于一些特殊的东西,例如,您可以执行以下操作:

oddFunction :: Integral a => [a] -> [a]
oddFunctiond list = do
  (True,y) <- zip (map odd list) list
  return y

此功能将做什么?您可以将此语句作为处理列表元素的规则来阅读。第一条语句将列表的一个元素绑定到 var y,但前提是 y 为奇数。如果 y 是偶数,则发生模式匹配失败,并且将调用 fail 。在列表的 monad 实例中,fail 只是 []。因此,该函数从列表中删除所有偶数元素。

(我知道,oddFunction = filter odd 会做得更好,但这只是一个例子)

I would strongly suggest you to read the chapter Desugaring of Do-blocks in the book Real-World haskell. It tells you, that you all are wrong. For a programmer, it's the natural way to use a lambda, but the do-block is implemented using functions which - if a pattern maching failuire occurs - will call the fail implementation of the according monad.

For instance, your case is like:

let f x =
        putStrLn "enter second line" >>
        let g y = return (x,y)
            g _ = fail "Pattern mismatched"
        in getLine >>= g
    f _ = fail "Pattern mismatched"
in getLine >>= f

In a case like this, this may be completely irrelevant. But consider some expression that involves pattern-matching. Also, you can use this effect for some special stuff, eg, you can do something like this:

oddFunction :: Integral a => [a] -> [a]
oddFunctiond list = do
  (True,y) <- zip (map odd list) list
  return y

What will this function do? You can read this statement as a rule for working with the elements of the list. The first statement binds an element of the list to the var y, but only if y is odd. If y is even, a pattern matching failure occurs and fail will be called. In the monad instance for Lists, fail is simply []. Thus, the function strips all even elements from the list.

(I know, oddFunction = filter odd would do this better, but this is just an example)

孤君无依 2024-09-25 23:29:10
getLine >>= \line1 ->
putStrLn "enter second line" >>
getLine >>= \line2 ->
return (line1, line2)

通常,foo <- bar 变为 bar >>= \foo ->baz 变为 baz >> (除非它是 do 块的最后一行,在这种情况下它只是保留 baz)。

getLine >>= \line1 ->
putStrLn "enter second line" >>
getLine >>= \line2 ->
return (line1, line2)

Generally foo <- bar becomes bar >>= \foo -> and baz becomes baz >> (unless it's the last line of the do-block, in which case it just stays baz).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文