- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想将 Haskell 添加到我的工具箱中,所以我正在努力通过 Real World Haskell .
在输入和输出一章中,在 the section on 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
在这个代码示例之后,作者继续说:
Notice that
hGetContents
handled all of the reading for us. Also, take a look atprocessData
. It's a pure function since it has no side effects and always returns the same result each time it is called. It has no need to know—and no way to tell—that its input is being read lazily from a file in this case. It can work perfectly well with a 20-character literal or a 500GB data dump on disk. (N.B. Emphasis is mine)
我的问题是:hGetContents
是怎么做到的?或其结果值实现此内存效率而无需 - 在本例中 - processData
“能够分辨”,并且仍然保持纯代码(即 processData
)带来的所有好处,特别是内存?
<- hGetContents inh
返回一个字符串所以 inpStr
绑定(bind)到 String
类型的值,这正是 processData
的类型接受。但是如果我正确理解 Real World Haskell 的作者,那么这个字符串与其他字符串不太一样,因为它没有完全加载到内存中(或者完全评估,如果存在未完全评估的字符串这样的东西...... .) 到调用 processData
时.
因此,另一种问我问题的方式是:如果 inpStr
在调用 processData
时未完全评估或加载到内存中,那么如果对 processData
的内存调用,它如何用于查找存在,无需先全面评估 inpStr
?
是否有 String
类型的实例?每个人的行为都不同,但不能在这个抽象层次上区分?
最佳答案
hGetContents
返回的String
与任何其他 Haskell 字符串没有区别。一般来说,Haskell 数据不会被完全评估,除非程序员采取额外的步骤来确保它是(例如 seq
、deepseq
、bang patterns)。
字符串被定义为(本质上)
data List a = Nil | Cons a (List a) -- Nil === [], Cons === :
type String = List Char
这意味着一个字符串要么是空的,要么是一个字符(头)和另一个字符串(尾)。由于 laziness ,尾部在内存中可能不存在,甚至可能是无穷大。在处理 String
时,Haskell 程序通常会检查它是 Nil
还是 Cons
,然后根据需要进行分支和继续。如果函数不需要计算尾部,它就不会。例如,这个函数只需要检查初始构造函数:
safeHead :: String -> Maybe Char
safeHead [] = Nothing
safeHead (x:_) = Just x
这是一个完全合法的字符串
allA's = repeat 'a' :: String
那是无限的。您可以明智地操作此字符串,但是如果您尝试打印所有字符串、计算长度或任何类型的无限遍历,您的程序将不会终止。但是您可以毫无问题地使用像 safeHead
这样的函数,甚至可以使用一些有限的初始子字符串。
但是,您认为发生了一些奇怪的事情的直觉是正确的。 hGetContents
是使用特殊函数 unsafeInterleaveIO 实现的,它本质上是一个编译器 Hook 到 IO
行为。越少说越好。
你是对的,如果不对参数进行完全评估,很难检查是否存在对函数的内存调用。但是,大多数编译器不执行此优化。问题在于,编译器很难确定何时值得内存调用,而且这样做很容易耗尽所有内存。还好有several memoizing libraries您可以在适当的时候使用它来添加内存。
关于lazy-evaluation - hGetContents 是如何实现内存效率的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19420450/
我有以下代码片段,我将其传递给 withFile : text => operation >=> print) bad file operation = (withFile file ReadMod
我想将 Haskell 添加到我的工具箱中,所以我正在努力通过 Real World Haskell . 在输入和输出一章中,在 the section on hGetContents 中,我遇到了这
我在 Haskell 中有一个程序从套接字获取所有输入并打印它。 main = withSocketsDo $ do sock IO () work
hGetContents返回一个惰性 String 对象,可在纯函数代码中使用该对象从文件句柄中读取。如果在读取此惰性字符串时发生 I/O 异常,则底层文件句柄将静默关闭,并且不会向惰性字符串添加任何
我试图理解haskell IO,但stdin的这个特性最终让我感到困惑: 当我尝试使用诸如 getContents 之类的功能时,例如: let main = do x<-getContents; p
当我尝试将 UTF8 文本文件读取为 Text 时,我尝试使用Data.Text.IO.readFile . 但是,当系统环境的区域设置不是 *.UTF8 时(特别是 c ),它不起作用。 它说hGe
我学习 Haskell。它工作正常: import System.IO main = do h >= \ cnt -> {- rest of do block -} {- rest of the
我在 Mac OSX 10.6.8 的终端中运行以下代码: find . -name \*.html -type f -exec pandoc -o {}.md {} \; 它解析了一些文档,但在很多
我正在使用 Haskell 编写解析器,但是这个错误是我无法逾越的墙。这是我的代码: main = do arguments <- getArgs let fileName = head
我是一名优秀的程序员,十分优秀!