我想将 Haskell 添加到我的工具箱中,所以我正在通过Real World Haskell工作。
在输入和输出一章中,hGetContents
我遇到了这个例子:
import System.IO
import Data.Char(toUpper)
main :: IO ()
main = do
inh <- openFile "input.txt" ReadMode
outh <- openFile "output.txt" WriteMode
inpStr <- hGetContents inh
let result = processData inpStr
hPutStr outh result
hClose inh
hClose outh
processData :: String -> String
processData = map toUpper
在此代码示例之后,作者继续说:
请注意,它
hGetContents
为我们处理了所有的阅读。另外,看看processData
。它是一个纯函数,因为它没有副作用,并且每次调用时总是返回相同的结果。在这种情况下,它不需要知道——<em>也没有办法知道——它的输入是从文件中懒惰地读取的。它可以与 20 个字符的文字或磁盘上的 500GB 数据转储完美配合。 (NB重点是我的)
我的问题是:如果没有——在这个例子中—— “能够分辨”,hGetContents
或者它的结果值如何实现这种内存效率,并且仍然保持纯代码(即)产生的所有好处,特别是记忆化?processData
processData
<- hGetContents inh
返回一个字符串,因此inpStr
绑定到 type 的值String
,这正是processData
接受的类型。但是,如果我正确理解 Real World Haskell 的作者,那么这个字符串与其他字符串不太一样,因为它没有完全加载到内存中(或完全评估,如果存在诸如未完全评估的字符串之类的东西...... .) 在调用processData
.
因此,问我的问题的另一种方式是:如果inpStr
在调用时没有完全评估或加载到内存中,那么如何在没有首先完全评估的情况下processData
使用它来查找是否存在记忆调用?processData
inpStr
是否存在String
每个行为不同但在这个抽象级别上无法区分的类型实例?