在 do 块中的 where 中使用来自外部作用域的变量

Using variable from outer scope in where in do block

我正在尝试在使用 where:

do 块中定义的操作中使用外部范围中定义的变量
module Main where

main :: IO ()
main = do
    outerVar <- return "a"
    doSomething
    where
        doSomething :: IO String
        doSomething = putStrLn ("outerVar: " ++ outerVar)

鉴于此片段,我试图理解为什么编译器 return 出现以下错误:

error: Variable not in scope: outerVar :: [Char]
  |
9 |         doSomething = putStrLn ("outerVar: " ++ outerVar)
  |

根据我的理解 - doSomething 函数应该创建某种 "closure" 来包含 outerVar 的值(我刚刚发现它被称为 free variable),但这并没有发生。

我花了很多时间试图弄清楚为什么会发生这个错误。我很尴尬,因为即使对我这样一个 Haskell 新手来说,这似乎也是一个应该显而易见的基本概念,但事实并非如此 - 希望我是错的。我在搜索 "where in do block scope"、"where closure" 或类似关键字时找不到任何答案。 This page that compares let and where doesn't mention my case, the closest example I've found is the first bit of code from here 其中涵盖了 "Lambda lifting" 主题。他们能够在 where 中定义的函数中使用来自外部作用域的 n 变量,但它不像我的情况那样在 do 块中。

所以我的问题是 - 为什么 outerVar 变量不在 doSomething 的范围内?

do 块只是使用 >>= 和 lambda 函数链接 monadic 值的语法糖。您的块首先由编译器翻译成:

return "a" >>= \outerVar -> doSomething
  where doSomething =...

现在应该很明显 outerVar 不在它作为参数的 lambda 之外的范围内。