惰性地评估Haskell中的一元函数
我似乎想不出一个解决这个问题的办法 我有这样的想法:惰性地评估Haskell中的一元函数,haskell,monads,lazy-evaluation,Haskell,Monads,Lazy Evaluation,我似乎想不出一个解决这个问题的办法 我有这样的想法: getFilePathForDay :: Day -> IO (Maybe FilePath) getFilePathForDays date days = do files <- mapM getFilePathForDay $ iterate (addDays 1) date return . take days . catMaybes $ files getFilePathForDay::
getFilePathForDay :: Day -> IO (Maybe FilePath)
getFilePathForDays date days = do
files <- mapM getFilePathForDay $ iterate (addDays 1) date
return . take days . catMaybes $ files
getFilePathForDay::Day->IO(可能是FilePath)
getFilePathForDays日期天数=do
文件代码将永远运行,因为在调用mapM
时,您试图对无限多的副作用计算排序
由于您事先不知道需要运行多少计算(如您使用的catMaybes
所示),因此必须将对getFilePathForDay
的调用与其余计算交错。这可以使用unsafeInterleaveIO
实现,但顾名思义,这不是推荐的方法
您可以通过以下方式手动实现此功能:
getFilePathForDays _ 0 = return []
getFilePathForDays date days = do
mpath <- getFilePathForDay date
case mpath of
Just path -> (path :) <$> remaining (days-1)
Nothing -> remaining days
where
remaining days = getFilePathForDays (addDays 1 date) days
getFilePathForDays\u0=return[]
getFilePathForDays日期天数=do
mpath(路径:)剩余(第1天)
无->剩余天数
哪里
剩余天数=getFilePathForDays(addDays 1日期)天
也许有一种更优雅的方法,但我现在还没有想到:)有时候懒惰IO是正确的方法。由于您有一个无限的、惰性的天数序列,并且您正在惰性地对该序列中的某些(动态)范围进行采样,因此我们也应该只按需访问文件系统
这可以通过unsafeInterleaveIO
完成:
import System.IO.Unsafe ( unsafeInterleaveIO )
-- return a lazy list of filepaths, pull as many as you need
getFilePathForDays :: Day -> Int -> IO [FilePath]
getFilePathForDays date days = do
let go (d:ds) = unsafeInterleaveIO $ do
f <- getFilePathForDay d
fs <- go ds
return (f:fs)
-- an infinite, lazy stream of filepaths
fs <- go (iterate (addDays 1) date)
return . take days . catMaybes $ fs
import System.IO.Unsafe(unsafeInterleaveIO)
--返回文件路径的延迟列表,根据需要提取任意数量的文件路径
getFilePathForDays::Day->Int->IO[FilePath]
getFilePathForDays日期天数=do
放手(d:ds)=不插手$do
为什么这需要在IO单子中?您正在测试文件是否存在?如果是这样的话,在生成文件路径之后就不能这样做吗?@Robin Green:也许Ratzes想从给定日期开始查找第一个n
现有文件。通过模式匹配在Maybes上生成列表听起来像是一个展开;也许有一种优雅的表达方式?@Dan:这也是我最初的想法,但不是很琐碎。我们想继续下去,直到我们得到一定数量的只
s,过滤掉无
s,而不是在第一个无
@Dan:是的,有一元序列展开,但在这种情况下,我们需要一个展开函数(生成路径)和一个折叠函数(只计算个数,并根据需要读取尽可能多的数据),两者都有副作用,需要以正确的方式交错。一个优雅的泛化当然存在,但它可能有一个神秘的名称,并且在类别附加程序包中。我们在标准库中的某个地方没有一个unfolm,这真是太傻了。中有一个。但是,是的,可能是一个很好的基础候选。如果你u将懒惰IO提取到一个函数中,比如lazyMapIO f(a:as)=unsafeInterleaveIO$do b alazySequenceIO
通常非常方便,但当然,由于(完全正确,但仍然…)的“懒惰IO是邪恶的”,它永远也不会进入基础暴民,除了我实际写的代码外,我在各个方面都同情他们:-)