在Haskell中实现窥视迭代器
我正在向Haskell移植一些广泛使用 偷窥迭代器。它本质上包装了一个集合,并提供了两个 功能,“下一步”和“偷看”。“下一步”功能使 迭代器并返回head元素,而“peek”函数 返回head元素而不推进迭代器。会是什么 把这个概念翻译成Haskell的优雅方式?我最好的主意是这样 far基本上是使用状态单子来跟踪当前状态 迭代器的位置。有没有更干净的方法在Haskell中实现窥视迭代器,haskell,Haskell,我正在向Haskell移植一些广泛使用 偷窥迭代器。它本质上包装了一个集合,并提供了两个 功能,“下一步”和“偷看”。“下一步”功能使 迭代器并返回head元素,而“peek”函数 返回head元素而不推进迭代器。会是什么 把这个概念翻译成Haskell的优雅方式?我最好的主意是这样 far基本上是使用状态单子来跟踪当前状态 迭代器的位置。有没有更干净的方法 (我也在初学者@上发布了这篇文章,但没有得到任何答案)副作用迭代器的想法与Haskell方法相反。你当然可以设计一个monad,但在这一点
(我也在初学者@上发布了这篇文章,但没有得到任何答案)副作用迭代器的想法与Haskell方法相反。你当然可以设计一个monad,但在这一点上,你使用Haskell作为(引用simonpj的话)世界上最好的命令式语言 在不了解更多您尝试移植的代码的情况下,我无法给出非常具体的建议,但以下是我的一般想法:
- 使用某种折叠实现您的迭代
- 传递给折叠操作的函数应由其他函数组成。可能由零个或多个“偷窥”操作加上一个“下一步”操作组成
a->b->a
,那么您的peek
和next
版本可能都有这种类型,您可以这样组合它们:
peek_then_next :: (a -> b -> a) -> (a -> b -> a) -> (a -> b -> a)
peek_then_next peek next = next'
where next' a b = let a' = peek a b
in next a' b
您将看到peek
和next
参数看起来都是相同的b
,但是peek
将信息累积到a'
中,然后由next
操作查看
您可以任意编写这些内容,然后将这些内容传递给
foldl
或类似的内容。通常在Haskell中,您可以计算无限列表(通常由递归函数生成),而不是迭代器。您不需要从迭代器中“获取元素”,只需沿着列表进行迭代(通常使用递归函数、折叠或映射等),然后查看列表中的元素。因为Haskell是懒惰的,所以它只在您需要时计算值
我认为您应该使用接受无限列表的递归函数来实现您的任务。要“偷看”,只需查看列表的第一个元素。(只要对列表进行索引,就可以根据需要“窥视”列表当前“头”后面的任意多个元素。)要“推进”迭代器,只需使用列表的尾部递归调用自己
type Iterator a = [a]
peek :: Iterator a -> a
peek = head
next :: Iterator a -> Iterator a
next = tail
您所描述的内容听起来像Haskell的常规内置单链表。甚至可能是。你可以在哈斯克尔做你想做的事,但要注意的是,这些都是重武器:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
class Iterator as a | as -> a where
peek :: as -> a
next :: as -> (as, a)
--sample implementation
instance Iterator [a] a where
peek as = head as
next as = (tail as, head as)
--sample use
main = print $ next $ [3,4]
--([4],3)
当然,迭代器
不会改变,它必须返回它的新版本(非常类似于随机数生成器),但我认为一些“可变”的东西在这里会被过度使用
也就是说,我认为在Haskell中,你真的应该使用更惯用的方式来做你想做的事情。也许你应该看看
阅读器
monad是如何工作的:你看过Data.Enumerator包了吗。它附带了一个peek函数@ErikHinton-鉴于问题描述,枚举数可能是极端的过度使用。