IO定义变量的范围

时间:2011-10-17 20:46:31

标签: haskell

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

例如:

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

这不起作用,因为s不在范围内。我做了一些研究来确认它并找到this文章:

  

与变量在所有定义范围内的let表达式不同,<-定义的变量仅在以下语句的范围内。

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

3 个答案:

答案 0 :(得分:6)

除了一般的let表单外,还有一个特殊的let表单,可以使用do语法来代替:

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

magic在块中的所有后续行中都可用。

答案 1 :(得分:1)

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

magic m = doMagic m

或者:

magic = \m-> doMagic m

并称之为:

putStrLn $ magic s

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

let magic_str = magic s in
  putStrLn magic_str

答案 2 :(得分:1)

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子句中使用它,并且会出现“not in scope”错误。

let有效,因为letwhere的解析方式不同。括号内容为清晰起见:

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

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