在Haskell中我们有一个功能readFile :: FilePath -> IO String.理解monad时我的问题是为什么要包装它IO?难道我们不能只写这样的函数:
(lines.readFile) path
Run Code Online (Sandbox Code Playgroud)
而不是
(readFile >>= lines) path
Run Code Online (Sandbox Code Playgroud)
IO包装器提供什么好处?
Haskell表达式是引用透明的.这意味着如果readFile真的有一个类型FilePath -> String,那么表达式readFile "a.txt"总会产生相同的结果.即使您读取文件,然后更改它,然后再次阅读,您将获得处于其第一状态的内容.
因此,我们需要在价值观和行动之间进行斗争,这IO就是为了什么.readFile "a.exe"在执行与之关联的操作之前,它不允许您在其他表达式中使用结果.因此,在更改文件后,您必须再次执行读取操作,以获取文件内容,因此您将能够看到更改.
应该注意的是,Haskell是一种函数式编程语言.在数学意义上,函数总是为相同的输入生成相同的值.
现在这个总是产生相同结果的要求会对事物产生很大的限制,因为读取文件的函数每次都必须产生相同的结果,即使文件稍后被更改.这显然不是我们真正想要的.
但是,有一种方法可以使函数式编程语言能够处理读取更改的文件.你所做的就是编写一个能产生计算机应该执行的动作的函数.因此,您可以执行由以下步骤组成的操作:
Read the file
Break it into lines
Change the even-numbered lines to uppercase
Output the lines to the screen
Run Code Online (Sandbox Code Playgroud)
这四项行动尚未执行.它们只是我们可能执行的一系列操作.函数可以在每次调用时返回完全相同的潜在动作序列,这使其成为一个合适的数学函数.
main :: IO aHaskell中的函数返回程序应执行的操作.它总是返回相同的动作,使其成为一个合适的数学函数.运行程序时,计算机会评估该main功能,产生计算机应执行的操作,然后计算机执行该操作.
记谱法将过程中的陌生感带走,让您感受到更加标准的编程语言.你有三个选择:
这些分别按以下方式完成:
action argsresult <- action argslet result = f . g . h . whateverCalculation $ value这类似于你所做的像C这样的命令式语言:
action(args);result = action(args);result = f(g(h(whateverCalculation(value))));