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,获取其结果,并将其绑定到xlet 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绑定而是<-.
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.你想得到的String是readFile- 而是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那么你可以使用=.
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是磁盘上文件的内容.