Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell IO操作的惰性评估_Haskell - Fatal编程技术网

Haskell IO操作的惰性评估

Haskell IO操作的惰性评估,haskell,Haskell,我试图用源->转换->接收风格编写代码,例如: let (|>) = flip ($) repeat 1 |> take 5 |> sum |> print 但我想使用IO来实现这一点。我有这样的印象,我的源可以是一个无限的IO操作列表,每一个都会在下游需要时得到评估。大概是这样的: -- prints the number of lines entered before "quit" is entered [getLine..] >>= takeWhile

我试图用
源->转换->接收
风格编写代码,例如:

let (|>) = flip ($)
repeat 1 |> take 5 |> sum |> print
但我想使用
IO
来实现这一点。我有这样的印象,我的源可以是一个无限的IO操作列表,每一个都会在下游需要时得到评估。大概是这样的:

-- prints the number of lines entered before "quit" is entered
[getLine..] >>= takeWhile (/= "quit") >>= length >>= print

我认为流媒体库可以做到这一点,但能否按照我的建议来做呢?

这似乎是本着这种精神:

let (|>) = flip ($)
let (.>) = flip (.)

getContents >>= lines .> takeWhile (/= "quit") .> length .> print
使用库中的、和函数:

导入流媒体
导入符合条件的流媒体。前奏为S
计数::IO()

count=do r这里的问题是
Monad
不是正确的抽象,尝试这样做会导致引用透明性被破坏的情况

首先,我们可以这样做:

module Main where

import System.IO.Unsafe (unsafePerformIO)
import Control.Monad(forM_)

lazyIOSequence :: [IO a] -> IO [a]
lazyIOSequence = pure . go where
    go :: [IO a] -> [a]
    go (l:ls) = (unsafePerformIO l):(go ls)


main :: IO ()
main = do
    l <- lazyIOSequence (repeat getLine)
    forM_ l putStrLn 
这只输出
Hello World
,因为我们不需要评估
l
中的任何一个。但是现在考虑替换最后一行如下:

main :: IO ()
main = do
    x <- lazyIOSequence (map (putStrLn . show) [1..])
    seq (head x) putStrLn "Hello World"
这很糟糕,我们仅仅通过评估一个值就改变了程序的结果。这在Haskell是不应该发生的,当你评估某件事情时,它应该只是评估它,而不是改变外部世界

因此,如果您将IO操作限制为读取文件之类的内容,那么您可能能够明智地惰性地评估这些内容,因为当您读取文件时,与程序正在执行的所有其他IO操作相关的内容并不重要。但通常情况下,您不希望在IO中允许这样做,因为跳过操作或以不同的顺序执行操作可能很重要(当然,更重要的是)。即使是在延迟读取文件的情况下,如果程序中的其他内容写入文件,那么无论是在写入操作之前还是之后对该列表求值,都会影响程序的输出,这同样会破坏引用的透明度(因为求值顺序应该不重要)


因此,对于IO操作的受限子集,您可以明智地在流类型上定义Functor、Applicative和Monad以惰性方式工作,但在IO Monad中这样做通常是一个雷区,通常是不正确的。相反,您需要一个专门的流类型,并且确实在许多流类型上定义了Functor、Applicational和Monad,因此您仍然可以使用所有喜爱的函数

是的,但我认为
getContents
是一个懒惰的行为。我对多重动作特别感兴趣。一般来说,是的。这正是
管道
导管
库(以及其他一些库)要做的事情。我自己也没有这方面的经验,所以示例必须来自其他人。相关人员:当然,这会起作用,但我的问题是为什么我需要流媒体库?为什么“正常”的哈斯克尔懒散还不够呢?
main :: IO ()
main = do
    l <- lazyIOSequence (map (putStrLn . show) [1..])
    putStrLn "Hello World"
main :: IO ()
main = do
    x <- lazyIOSequence (map (putStrLn . show) [1..])
    seq (head x) putStrLn "Hello World"
1
Hello World