haskell 中的等号 (=) 与左箭头 (<-) 符号
Equal (=) Vs left arrow (<-) symbols in haskell
工作代码:
import System
main = do
[file1, file2] <- getArgs
--copy file contents
str <- readFile file1
writeFile file2 str
崩溃代码:
import System
main = do
[file1, file2] = getArgs
str = readFile file1
writeFile file2 str
当我尝试时,它抛出了一个错误:
a.hs:6:18: parse error on input '='
那么,<-
与 =
有何不同?
do
x <- y
f x
相当于:
y >>= \x -> f x
do
let x = y
f x
相当于
f y
即let
/=
没有单子绑定,而 <-
有。
要了解真正的区别,您必须了解 monad,以及@rightfold 在他们的回答中描述的脱糖。
对于 IO monad 的特定情况,如您的 getArgs
示例中所示,可以做出如下粗略但有用的直觉:
x <- action
运行s 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
再次声明:此比较仅关注 IO。对于其他 monad,你需要检查 >>=
实际上是什么,并考虑 do
.
的脱糖
代码无法编译,因为类型不匹配。让我们加载一个 GHCI 会话并查看您正在使用的函数的类型 -
> :t writeFile
writeFile :: FilePath -> String -> IO ()
>
> :t readFile
readFile :: FilePath -> IO String
所以writeFile
想要一个FilePath
和一个String
。你想从 readFile
得到 String
- 但是 readFile
returns IO String
而不是 String
.
Haskell是一门很有原则的语言。它在 pure 函数(每次使用相同的参数调用时给出相同的输出)和 impure 代码(可能给出不同的结果,例如,如果函数取决于某些用户输入)。处理 input/output (IO) 的函数总是有一个标有 IO
的 return 类型。类型系统确保你不能在纯函数中使用不纯的 IO
代码——例如,不是 returning a String
函数 readFile
returns an IO String
.
这是 <-
符号的重要之处。它允许您获取 IO
内的 String
并确保无论您对该字符串做什么,您正在定义的函数将始终标记为 IO
。比较以下-
> let x = readFile "tmp.txt"
> :t x
x :: IO String
这不是我们想要的,对这个
> y <- readFile "tmp.txt"
> :t y
y :: String
这就是我们想要的。如果你有一个 return 是 IO a
的函数并且你想访问 a
,你需要使用 <-
将结果分配给一个名称。如果您的函数没有 return IO a
,或者如果您不想在 IO
内获取 a
那么您可以使用 =
.
let x = readFile file1
这执行操作“readFile file1
”并将操作存储在x
。
x <- readFile file1
这执行动作“readFile file1
”并将动作的结果存储在x
中。
在第一个例子中,x
是一个未执行的I/O动作对象。在第二个示例中,x
是磁盘上文件的内容。
工作代码:
import System
main = do
[file1, file2] <- getArgs
--copy file contents
str <- readFile file1
writeFile file2 str
崩溃代码:
import System
main = do
[file1, file2] = getArgs
str = readFile file1
writeFile file2 str
当我尝试时,它抛出了一个错误:
a.hs:6:18: parse error on input '='
那么,<-
与 =
有何不同?
do
x <- y
f x
相当于:
y >>= \x -> f x
do
let x = y
f x
相当于
f y
即let
/=
没有单子绑定,而 <-
有。
要了解真正的区别,您必须了解 monad,以及@rightfold 在他们的回答中描述的脱糖。
对于 IO monad 的特定情况,如您的 getArgs
示例中所示,可以做出如下粗略但有用的直觉:
x <- action
运行s IOaction
, 获取其结果,并将其绑定到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
再次声明:此比较仅关注 IO。对于其他 monad,你需要检查 >>=
实际上是什么,并考虑 do
.
代码无法编译,因为类型不匹配。让我们加载一个 GHCI 会话并查看您正在使用的函数的类型 -
> :t writeFile
writeFile :: FilePath -> String -> IO ()
>
> :t readFile
readFile :: FilePath -> IO String
所以writeFile
想要一个FilePath
和一个String
。你想从 readFile
得到 String
- 但是 readFile
returns IO String
而不是 String
.
Haskell是一门很有原则的语言。它在 pure 函数(每次使用相同的参数调用时给出相同的输出)和 impure 代码(可能给出不同的结果,例如,如果函数取决于某些用户输入)。处理 input/output (IO) 的函数总是有一个标有 IO
的 return 类型。类型系统确保你不能在纯函数中使用不纯的 IO
代码——例如,不是 returning a String
函数 readFile
returns an IO String
.
这是 <-
符号的重要之处。它允许您获取 IO
内的 String
并确保无论您对该字符串做什么,您正在定义的函数将始终标记为 IO
。比较以下-
> let x = readFile "tmp.txt"
> :t x
x :: IO String
这不是我们想要的,对这个
> y <- readFile "tmp.txt"
> :t y
y :: String
这就是我们想要的。如果你有一个 return 是 IO a
的函数并且你想访问 a
,你需要使用 <-
将结果分配给一个名称。如果您的函数没有 return IO a
,或者如果您不想在 IO
内获取 a
那么您可以使用 =
.
let x = readFile file1
这执行操作“readFile file1
”并将操作存储在x
。
x <- readFile file1
这执行动作“readFile file1
”并将动作的结果存储在x
中。
在第一个例子中,x
是一个未执行的I/O动作对象。在第二个示例中,x
是磁盘上文件的内容。