在haskell中等于(=)Vs左箭头(< - )符号

45 haskell

工作代码:

import System
main = do
     [file1, file2] <- getArgs
     --copy file contents
     str <- readFile file1
     writeFile file2 str
Run Code Online (Sandbox Code Playgroud)

崩溃的代码:

import System
main = do
       [file1, file2] = getArgs
       str = readFile file1
       writeFile file2 str
Run Code Online (Sandbox Code Playgroud)

当我尝试时,它抛出一个错误:

a.hs:6:18:输入'='解析错误

那么,如何不同是<-=

chi*_*chi 87

要理解真正的差异,你必须了解monad,以及@rightfold在他们的答案中所描述的堕落.

对于IO monad的特定情况,如在您的getArgs示例中,粗略但有用的直觉可以如下:

  • x <- action 运行 IO action,获取其结果,并将其绑定到x
  • let x = action定义x为等同于action,但不运行任何东西.稍后,您可以使用y <- x含义y <- action.

来自允许闭包的命令式语言的程序员可以使用Javascript绘制这种粗略的并行比较:

var action = function() { print(3); return 5; }

// roughly equivalent to x <- action
print('test 1')
var x = action()  // output:3
// x is 5

// roughly equivalent to let y = action
print('test 2')
var y = action    // output: nothing
// y is a function

// roughly equivalent to z <- y
print('test 3')
var z = y()       // output:3
// z is 5
Run Code Online (Sandbox Code Playgroud)

再说一遍:这个比较只关注IO.对于其他monad,你需要检查>>=实际是什么,并考虑desugaring do.


rig*_*old 48

do
    x <- y
    f x
Run Code Online (Sandbox Code Playgroud)

相当于:

y >>= \x -> f x
Run Code Online (Sandbox Code Playgroud)
do
    let x = y
    f x
Run Code Online (Sandbox Code Playgroud)

相当于

f y
Run Code Online (Sandbox Code Playgroud)

ie let/ =没有monadic绑定而是<-.

  • @ user2407038不,他们完全是一回事.没有一个区别. (10认同)

Chr*_*lor 15

代码无法编译,因为类型不匹配.让我们加载GHCI会话并查看您正在使用的函数类型 -

> :t writeFile
writeFile :: FilePath -> String -> IO ()
>
> :t readFile
readFile :: FilePath -> IO String
Run Code Online (Sandbox Code Playgroud)

所以writeFile想要一个FilePath和一个String.你想得到的StringreadFile- 而是readFile返回IO String而不是String.

Haskell是一种非常有原则的语言.它区分函数(每次使用相同的参数调用时产生相同的输出)和不纯的代码(可能会产生不同的结果,例如,如果函数依赖于某些用户输入).处理输入/输出(IO)的函数始终具有标记为的返回类型IO.类型系统确保您不能IO在纯函数中使用不纯的代码 - 例如,而不是返回String函数readFile返回一个IO String.

这是<-符号很重要的地方.它允许您进入String内部,IO并确保无论您使用该字符串做什么,您定义的功能将始终标记为IO.比较以下 -

> let x = readFile "tmp.txt"
> :t x
x :: IO String
Run Code Online (Sandbox Code Playgroud)

这不是我们想要的

> y <- readFile "tmp.txt"
> :t y
y :: String
Run Code Online (Sandbox Code Playgroud)

这就是我们想要的.如果您有一个返回a IO a并且想要访问的函数,则a需要使用<-将结果分配给名称.如果你的功能没有返回IO a,或者如果你不想进入a内部IO那么你可以使用=.

  • OP的代码有*语法错误*.似乎应该在隐藏它背后的类型错误之前解决. (2认同)

Mat*_*hid 13

let x = readFile file1
Run Code Online (Sandbox Code Playgroud)

这需要在行动" readFile file1",并存储在行动x.

x <- readFile file1
Run Code Online (Sandbox Code Playgroud)

这将执行操作" readFile file1"并将操作结果存储在其中x.

在第一个示例中,x是一个未执行的I/O操作对象.在第二个示例中,x是磁盘上文件的内容.