在Haskell的另一个函数中保持变量 [英] Keep variable inside another function in Haskell
问题描述
askName = do
name< - getLine
return()
main :: IO()
main = do
putStrLn再次问候,你叫什么名字?
askName
但是,如何在我的 main
askName中的变量名称?
这是我第二次尝试:
askUserName = do
putStrLn你好,你叫什么名字?
name< - getLine
返回名称
sayHelloUser name = do
putStrLn(Hey++ name ++,you rock!)
main = do
askUserName>> = sayHelloUser
I现在可以以回调方式重新使用名称
,但是如果在main中我想再次调用名称,我该怎么做? (避免在主目录中显示 name< - getLine
)
我们可以想象,为了打印它而提出这个名称,然后我们重写它。
在伪代码中,我们有
main =
print你的名字是什么
绑定varname和userReponse
print varname
然后你的问题涉及到第二条指令。
看看这个指令的语义。
$ b
- userReponse 是一个返回用户输入(getLine)的函数
- varname 是一个var
- 绑定 var with fun :是一个将var(varname)与一个函数(getLine)的输出相关联的函数。
正如你在Haskell中所知道的那样,一切都是一个函数,那么我们的语义就不太合适。
为了尊重这个习惯用法,我们需要重新审视它。根据后面的反思,我们的 bind 函数的语义变为绑定 fun >
由于我们不能有变量,为了将参数传递给函数,我们需要乍看之下调用另一个函数,以便生成它们。因此,我们需要一种链接两个函数的方法,它正是 bind 应该执行的操作。此外,正如我们的示例所示,评估顺序应该受到尊重,并且这会引导我们进行以下重写 绑定 fun 这表明绑定更像是一个函数,它是一个运算符。 另外,我们知道一个函数取0 ,一个或多个参数并返回0,1个或多个参数。 等一下,绑定运算符与点运算符的用法有何不同为两个功能的组成? 它有很大的不同,因为我们忽略了一个重要的信息,bind并不链接两个函数,但它是链式两个 computations unit 。这就是为什么我们要定义这个操作符的关键。 让我们将一个全局计算写成计算单元的序列。 由于这个阶段是一个 strong>可以被定义为计算单元的集合,其中包含两个运算符>> = ,>> 。 我们如何在计算机科学中表示 set ? 然后,全局计算是容器,其中包含一些计算单元。在这个容器上,我们可以定义一些运算符,允许我们从计算单元移动到下一个运算符,考虑或不考虑后面的结果,这是我们的>> = 和>> 运算符。 因为它是容器,所以我们需要一种将注入值的方法,这是通过返回功能。将一个对象注入到计算中,您可以通过签名来检查它。 因为它是一个 strong>我们需要一种方法来管理失败,这由失败函数完成。 这里我有意包含main函数的签名,我们处于全局 IO计算的事实以及由此产生的输出为()(作为练习在ghci中输入 $:t print )。 然后写 正如您应该怀疑的那样,我们当然有一个特殊的语法来处理<在计算环境中绑定
然后,对于所有函数f和g,我们有使用 f 绑定 g。
在haskell中我们注意到了这一点
f> gt; = g
我们可以改进我们的 bind 运算符的定义。
事实上,当f doesn '返回任何结果我们注意>> = 为>>
应用这些反射到我们的伪代码导致我们
main = print你叫什么名字>> getLine>> = print
f0>> = f1>> f2>> f3 ...>> = fn
通常作为容器。
return :: a - > ma - m表示容器,然后全局计算
实际上,计算的接口由一个class
class计算
return - 在计算中注入一个对象
>> = - - 链式计算
>> - 链式计算,省略第一个结果
失败 - 管理计算失败
main :: IO()
main = return什么是你的名字>> =打印>> getLine>> = print
如果我们更注重>> = 的定义,我们可以使用下面的语法:
f>>> = g< => (β>>)和f>> g => f>> =(\_-> g)
main :: IO()
main =
返回你叫什么名字>> = \ x - >
print x>> = \_ - >
getLine>> = \ x - >
print x
然后我们以前的代码变成了do语法
<$ p $
main :: IO()
main = do
x< - return你叫什么名字
_< - print x
x< - getLine
print x
如果您想了解更多关于 monad
正如左边提到的那样,我的初步结论有点太热心了你应该感到震惊,因为我们已经打破了参照透明度 law(x在我们的指令序列中取两个不同的值),但它不再重要,因为我们进入了一个计算和一个计算后面定义的是一个容器,我们可以从中导出一个接口,并且该接口被设计为ma nage,作为解释,与现实世界相对应的不纯的世界。 I am lost in this concept. This is my code and what it does is just asking what is your name. However, How can I access in my This is my second attempt: I can now re-use the We can imagine that you ask the name in order to print it, then let's rewrite it. Your question then concern the second instruction. Or as you know in haskell everything is a function then our semantic is not well suited. As we cannot have variable, to pass argument to a function, we need, at a first glance, to call another function, in order to produce them. Thus we need a way to chain two functions, and it's exactly what's bind is supposed to do. Furthermore, as our example suggest, an evaluation order should be respected and this lead us to the following rewriting with fun bind fun That's suggest that bind is more that a function it's an operator. Furthermore, as we know that a function take 0, 1 or more argument and return 0, 1 or more argument. Wait a minute, How the bind operator differ from the dot operator use for the composition of two function ? It's differ a lot, because we have omit an important information, bind doesn't chain two function but it's chain two computations unit. And that's the whole point to understand why we have define this operator. Let's write down a global computation as a sequence of computation unit. As this stage a global computation could be define as a set of computation unit with two operator >>=, >>. How do we represent set in computer science ? Then a global computation is a container which contain some computation unit. On this container we could define some operator allowing us to move from a computation unit to the next one, taking into account or not the result of the later, this is ours >>= and >> operator. As it's a container we need a way to inject value into it, this is done by the return function. Which take an object and inject it into a computation, you could check it through is signature. As it's a computation we need a way to manage a failure, this done by the fail function. Now we can refine our code as follow Here I have intentionally include the signature of the main function, to express the fact that we are in the global IO computation and the resulting output with be () (as an exercise enter $ :t print in ghci). And then write As you should suspect, we certainly have a special syntax to deal with bind operator in computational environment. You're right this is the purpose of do syntax If you want to know more take a look on monad As mentioned by leftaroundabout, my initial conclusion was a bit too enthusiastic You should be shocked, because we have break referential transparency law (x take two different value inside our sequence of instruction), but it doesn't matter anymore,because we are into a computation, and a computation as defined later is a container from which we can derive an interface and this interface is designed to manage, as explain, the impure world which correspond to the real world. 这篇关于在Haskell的另一个函数中保持变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!askName = do
name <- getLine
return ()
main :: IO ()
main = do
putStrLn "Greetings once again. What is your name?"
askName
main
the variable name taken in 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
name
in a callback way, however if in main I want to call name again, how can I do that? (avoiding to put name <- getLine
in the main, obviously)
In pseudo code, we have main =
print "what is your name"
bind varname with userReponse
print varname
Take a look about the semantic of this one.
We need to revisit it in order to respect this idiom. According to the later reflexion the semantic of our bind function become bind fun with fun
Then for all function f and g we have with f bind g.
In haskell we note this as follow f >>= g
We could refine our definition of our bind operator.
In fact when f doesn't return any result we note >>= as >>
Applying, theses reflexions to our pseudo code lead us to main = print "what's your name" >> getLine >>= print
f0 >>= f1 >> f2 >> f3 ... >>= fn
Usually as container. return :: a -> m a -- m symbolize the container, then the global computation
In fact the interface of a computation is define by a class 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
main :: IO ()
main = return "What's your name" >>= print >> getLine >>= print
If we take more focus on the definition for >>=, we can emerge the following syntax f >>= g <=> f >>= (\x -> g) and f >> g <=> f >>= (\_ -> g)
main :: IO ()
main =
return "what's your name" >>= \x ->
print x >>= \_ ->
getLine >>= \x ->
print x
Then our previous code become, with do syntaxmain :: IO ()
main = do
x <- return "what's your name"
_ <- print x
x <- getLine
print x