理解`let`表达式中的IO()类型

Kev*_*ith 15 haskell

鉴于:

?: let f = putStrLn "foo" in 42
42
Run Code Online (Sandbox Code Playgroud)

什么是f类型?为什么"foo"在显示结果之前没有打印42?

最后,为什么以下不起作用?

?: :t f

<interactive>:1:1: Not in scope: ‘f’
Run Code Online (Sandbox Code Playgroud)

Vai*_*gar 13

什么是f类型?

正如您已经正确识别的那样,IO ()可以将其视为一个不会返回任何有用的IO操作(())

为什么在显示结果之前不会打印"foo" 42?

Haskell被懒惰地评估,但seq在这种情况下甚至还不够.如果表达式返回IO操作,则只会在REPL中执行IO操作.只有在返回时,才会在程序中执行IO操作main.但是,有办法解决这个限制.

最后,为什么以下不起作用?

Haskell let在表达式的范围内命名一个值,因此在评估表达式之后f超出范围.


chi*_*chi 10

let f = ...简单地定义f,并且不"运行"任何东西.它与命令式编程中的新函数的定义模糊地类似.

您的完整代码let f = putStrLn "foo" in 42可能会被松散地翻译成

{
  function f() {
     print("foo");
  }
  return 42;
}
Run Code Online (Sandbox Code Playgroud)

你不会指望上面打印任何东西,对吗?

相比之下,let f = putStrLn "foo" in do f; f; return 42类似于

{
  function f() {
     print("foo");
  }
  f();
  f();
  return 42;
}
Run Code Online (Sandbox Code Playgroud)

通信并不完美,但希望你能得到这个想法.


Jok*_*ter 7

f将是类型IO ().

"foo"没有打印,因为f它没有"绑定"到现实世界.(我不能说这是一个友好的解释.如果这听起来很废话,你可能想参考一些教程来了解Monad和懒惰评估的想法).

let name = value in (scope)使值可用,但不在范围之外,因此:t不会在ghci的顶级范围内找到它.

let没有in使它可用:t(此代码仅在ghci中有效):

> let f = putStrLn "foo"
> :t f
f :: IO ()
Run Code Online (Sandbox Code Playgroud)