简体   繁体   English

Haskell:理解bind和>>函数

[英]Haskell: Understanding the bind and >> functions

I have the following Haskell expression: 我有以下Haskell表达式:

a = getLine >>= putStrLn . filter isDigit >> a

I am having trouble understanding how the above expression works. 我无法理解上述表达式的工作原理。 I know the >>= function takes a monadic value and a function (that takes a normal value and returns a monadic value), and returns a monadic value. 我知道>>=函数采用monadic值和函数(采用正常值并返回monadic值),并返回monadic值。

I know that getLine and putStrLn have the following type declarations: 我知道getLineputStrLn具有以下类型声明:

getLine :: IO String 
putStrLn :: String -> IO ()

So the following part of expression: 所以表达的以下部分:

a = getLine >>= putStrLn . filter isDigit

Would return an IO () . 会返回一个IO () However, the function >> takes a first monadic value and a second monadic value and returns the second monadic value. 但是,函数>>取第一个monadic值和第二个monadic值并返回第二个monadic值。

Given the original expression, the first argument passed to >> would be of type IO String . 给定原始表达式,传递给>>的第一个参数将是IO String类型。 The second argument is a . 第二个参数是a

My question is, what is the type of a , and how does the above expression work to continually take user input and print only the numeric part of the input back to the screen? 我的问题是, a的类型是什么,以及上述表达式如何继续用户输入并仅将输入的数字部分打印回屏幕? Any insights are appreciated. 任何见解都表示赞赏。

Note : I renamed the a function to readPrintLoop as suggested by @SamuelBarr , since that avoids some confusion. 注意 :我按照readPrintLoop建议将a函数重readPrintLoopreadPrintLoop ,因为这样可以避免一些混淆。

My question is, what is the type of readPrintLoop , and how does the above expression work to continually take user input and print only the numeric part of the input back to the screen? 我的问题是, readPrintLoop的类型是readPrintLoop ,以及上述表达式如何工作以持续获取用户输入并仅将输入的数字部分打印回屏幕?

readPrintLoop has type: readPrintLoop :: IO a so it is an IO . readPrintLoop类型为: readPrintLoop :: IO a所以它是一个IO The a can be any type, since we never "return" that value, we will never end this function. a可以是任何类型,因为我们永远不会“返回”那个值,我们永远不会结束这个功能。

The function is constantly repeated because readPrintLoop is defined in terms of itself. 该函数不断重复,因为readPrintLoop是根据自身定义的。 readPrintLoop is defined as: readPrintLoop定义为:

readPrintLoop :: IO a
readPrintLoop = getLine >>= putStrLn . filter isDigit >> readPrintLoop

We here thus have infinite recursion, since eventually you will run into a , and thus replace that with another getLine >>= putStrLn . filter isDigit >> a 因此,我们在这里有无限递归,因为最终你会遇到a ,然后用另一个getLine >>= putStrLn . filter isDigit >> a替换它getLine >>= putStrLn . filter isDigit >> a getLine >>= putStrLn . filter isDigit >> a and so on. getLine >>= putStrLn . filter isDigit >> a等等。

However, the function >> takes a first monadic value and a second monadic value and returns the second monadic value. 但是,函数>>取第一个monadic值和第二个monadic值并返回第二个monadic值。

(>>) is equivalent to: (>>)相当于:

(>>) :: Monad m => m a -> m b -> m b
u >> v = u >>= (\_ -> v)

so the implementation of a is equivalent to: 所以执行a等同于:

readPrintLoop :: IO a
readPrintLoop = getLine >>= putStrLn . filter isDigit >>= \_ -> readPrintLoop

Here the underscore variable _ will be passed () . 这里的下划线变量_将被传递()

a  =  getLine >>= putStrLn . filter isDigit

is not "the part of expression". 不是 “表达的一部分”。

      getLine >>= putStrLn . filter isDigit

is the part of the expression. 是表达的一部分。 And it does not " return IO () ". 并且它不会“ 返回 IO () ”。 It has the type IO () (which you've correctly inferred (*) ). 具有类型IO () (您已正确推断(*) )。 It is a "monadic value" that you talk about. 你所谈论的“一元价值”

Giving it a name, any name , 给它一个名字, 任何名字

ioAction :: IO ()
ioAction  =  getLine >>= (putStrLn . filter isDigit)

we end up with 我们最终得到了

a  =  ioAction >> a 
----------------------------------
 (>>)     :: IO a -> IO b -> IO b
 ioAction :: IO ()
 a        ::         IO b
----------------------------------
 a        ::                 IO b

and everything typechecks. 以及所有的东西。

The semantics of a in a in的语义

a  =  ((>>) ioAction) a

is defined by the semantics of >> . >>的语义定义。


(*) (*)

---------------------------------------------------- 
    (>>=)                     :: m a -> (a -> m b) -> m b
    getLine                   :: IO String                   m a
    putStrLn                  ::    String -> IO ()          
    putStrLn . filter isDigit ::    String -> IO ()            a -> m b
----------------------------------------------------        ------------
 getLine >>= (putStrLn . filter isDigit)   :: IO ()          m        b

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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