IO定义变量的范围

发布于 2024-12-10 03:38:23 字数 568 浏览 0 评论 0原文

我发现在 Haskell 中进行 IO 时,使用 <- 运算符分配的变量仅在紧随其后的语句的范围内 - 而不是在 where 子句中。

例如:

main :: IO()
main =  do
          s <- getLine
          putStr magic
            where
              magic = doMagic s

这将不起作用,因为 s 不在范围内。我做了一些研究来证实这一点,并发现这篇文章:

let 表达式中变量的作用域涵盖所有定义不同,<- 定义的变量仅在以下语句的作用域内。

那么如何才能使 s 可在 where 子句中使用呢?

I've discovered that when doing IO in Haskell, variables that are assigned using the <- operator are only in scope for the statements immediately after them - not in where clauses.

For example:

main :: IO()
main =  do
          s <- getLine
          putStr magic
            where
              magic = doMagic s

This won't work as s is not in scope. I did some research to confirm it and found this article:

Unlike a let expression where variables are scoped over all definitions, the variables defined by <- are only in scope in the following statements.

So how can I make s available for use in the where clause?

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

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

发布评论

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

评论(3

电影里的梦 2024-12-17 03:38:23

除了一般的 let 形式之外,还有一种特殊的 let 形式可以与 do 语法一起使用,您可以使用它来代替:

main :: IO()
main =  do
          s <- getLine
          let magic = doMagic s
          putStr magic

magic 在块中的所有以下行中都可用。

In addition to the general let form, there's a special let form for use with do syntax you can use instead:

main :: IO()
main =  do
          s <- getLine
          let magic = doMagic s
          putStr magic

magic is available in all following lines in the block.

生生漫 2024-12-17 03:38:23

嗯,magic 是一个函数。因此,您可以执行以下操作:

magic m = doMagic m

或者:

magic = \m-> doMagic m

并像这样调用它:

putStrLn $ magic s

当然,正如您已经研究过的那样,当您可以重用计算的 magic 时,明智的做法是使用 let ... 在 表达式中,并嵌套调用:

let magic_str = magic s in
  putStrLn magic_str

Well, magic is a function. Therefore you can do something like:

magic m = doMagic m

Or:

magic = \m-> doMagic m

And call it like so:

putStrLn $ magic s

Of course, as you already researched, the sensible thing to do when you can reuse your computed magic is to use a let ... in expression, and nest the calls:

let magic_str = magic s in
  putStrLn magic_str
梦旅人picnic 2024-12-17 03:38:23

let 是处理这个问题的实用方法。但也许值得了解一下这里到底发生了什么。 do 语句并不是导致范围界定问题的原因。

请记住,这

 main =  do
      s <- getLine
      putStr magic
        where
          magic = doMagic s

相当于:

main = getline >>= \s ->
       putStr magic
          where magic = doMagic s

如果我们放入一些括号,则为:

main = getline >>= (\s -> putStr magic) where magic = doMagic s

这就是 s 的作用域的来源:它是 lambda 表达式的参数,并且仅存在于该 lambda 表达式中。尝试在该 lambda 之外的 where 子句中使用它,您会收到“不在范围内”错误。

let 之所以有效,是因为 letwhere 解析方式不同。为了清楚起见,用括号表示:

foo   = (\x -> let y = x in y)  -- Works fine
foo'' = (\x -> y) where y = x   -- y is not in scope

这就是导致问题的原因;它不是特定于 IO 或 do 语句。

let is the practical way to handle this. But it may be worth unpacking what's really going on here. The do statement isn't what's causing the scoping trouble.

Remember that

 main =  do
      s <- getLine
      putStr magic
        where
          magic = doMagic s

is equivalent to this:

main = getline >>= \s ->
       putStr magic
          where magic = doMagic s

If we put in some parentheses, this is:

main = getline >>= (\s -> putStr magic) where magic = doMagic s

This is where the scope of s comes from: it's the argument to a lambda expression, and it only exists within that lambda expression. Try to use it in a where clause outside of that lambda, and you get a "not in scope" error.

let works because let and where parse differently. With parentheses for clarity:

foo   = (\x -> let y = x in y)  -- Works fine
foo'' = (\x -> y) where y = x   -- y is not in scope

This is what's causing the problem; it's not specific to IO, or to do statements.

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