我迷失在这个概念中.这是我的代码,它的作用就是询问你的名字是什么.
askName = do
name <- getLine
return ()
main :: IO ()
main = do
putStrLn "Greetings once again. What is your name?"
askName
Run Code Online (Sandbox Code Playgroud)
但是,如何在我main的askName中获取变量名称?
这是我的第二次尝试:
askUserName = do
putStrLn "Hello, what's your name?"
name <- getLine
return name
sayHelloUser name = do
putStrLn ("Hey " ++ name ++ ", you rock!")
main = do
askUserName >>= sayHelloUser
Run Code Online (Sandbox Code Playgroud)
我现在可以name以回调方式重新使用,但是如果在main中我想再次调用name,我该怎么做?(name <- getLine 显然避免放入主体)
我们可以想象你问这个名字是为了打印它,然后让我们改写它.
在伪代码中,我们有
main =
print "what is your name"
bind varname with userReponse
print varname
Run Code Online (Sandbox Code Playgroud)
然后你的问题涉及第二条指令.
看看这个的语义.
或者你知道在haskell中,一切都是函数,那么我们的语义就不太适合了.
我们需要重新审视它以尊重这个习语.据后来的反思语义我们的绑定功能成为绑定 的乐趣 与 乐趣
由于我们不能有变量,要将参数传递给函数,我们首先需要调用另一个函数,以便生成它们.因此,我们需要一种链接两个函数的方法,而这正是bind应该做的事情.此外,正如我们的示例所示,应该尊重评估顺序,这将引导我们进行以下重写,并 带来有趣的 绑定 乐趣
这表明bind更像是一个函数,它是一个运算符.
然后对于所有函数f和g,我们用 f bind g.
在haskell中,我们注意到如下
f >>= g
Run Code Online (Sandbox Code Playgroud)
此外,我们知道函数需要0,1个或更多参数并返回0,1个或更多参数.
我们可以改进我们的绑定运算符的定义.
事实上,当f没有返回任何结果时,我们注意到>> = as >>
Apply,这些对我们的伪代码的反思引导我们
main = print "what's your name" >> getLine >>= print
Run Code Online (Sandbox Code Playgroud)
等一下,绑定运算符如何区别于点运算符用于两个函数的组合?
它有很大的不同,因为我们省略了一个重要的信息,绑定不链接两个函数但它是链的两个计算单元.这就是理解为什么我们定义这个运算符的重点.
让我们将全局计算写为计算单元序列.
f0 >>= f1 >> f2 >> f3 ... >>= fn
Run Code Online (Sandbox Code Playgroud)
在此阶段,全局计算可以定义为一组具有两个运算符>> =,>>的计算单元.
我们如何代表设置在计算机科学?
通常作为容器.
然后全局计算是包含一些计算单元的容器.在这个容器上我们可以定义一些运算符,允许我们从计算单元移动到下一个,考虑到或不考虑后者的结果,这是我们的>> =和>>运算符.
因为它是一个容器,我们需要一种为其注入价值的方法,这是由return函数完成的.拿一个对象并将其注入计算中,你可以检查它是签名.
return :: a -> m a -- m symbolize the container, then the global computation
Run Code Online (Sandbox Code Playgroud)
由于这是一个计算,我们需要一种管理故障的方法,这由失败函数完成.
实际上,计算的接口是由类定义的
class Computation
return -- inject an objet into a computation
>>= -- chain two computation
>> -- chain two computation, omitting the result of the first one
fail -- manage a computation failure
Run Code Online (Sandbox Code Playgroud)
现在我们可以改进我们的代码如下
main :: IO ()
main = return "What's your name" >>= print >> getLine >>= print
Run Code Online (Sandbox Code Playgroud)
在这里,我有意包含main函数的签名,以表达我们在全局IO计算中的事实以及使用be ()得到的输出(作为练习在ghci中输入$:t print).
如果我们更多地关注>> =的定义,我们可以使用以下语法
f >>= g <=> f >>= (\x -> g) and f >> g <=> f >>= (\_ -> g)
Run Code Online (Sandbox Code Playgroud)
然后写
main :: IO ()
main =
return "what's your name" >>= \x ->
print x >>= \_ ->
getLine >>= \x ->
print x
Run Code Online (Sandbox Code Playgroud)
正如您应该怀疑的那样,我们当然有一种特殊的语法来处理计算环境中的绑定运算符.你是对的这是做语法的目的
然后我们以前的代码变成了,用do语法
main :: IO ()
main = do
x <- return "what's your name"
_ <- print x
x <- getLine
print x
Run Code Online (Sandbox Code Playgroud)
如果你想了解更多,请看看monad
如左下图所述,我的初步结论有点太热情了
你应该感到震惊,因为我们有破坏参照透明度法(x在我们的指令序列中取两个不同的值),但它不再重要,因为我们进入计算,后面定义的计算是一个容器来自我们可以派生出一个界面,这个界面旨在解决与现实世界相对应的不纯净世界.