我将一些代码移植到了广泛使用 peeking迭代器的概念的Haskell中。它基本上包装了一个集合,并提供了两个“下一个”和“窥视”功能。 “next”函数使迭代器前进 并返回head元素,而“peek”函数 返回head元素而不前进迭代器。什么是 一个优雅的方式来将这个概念转化为Haskell?我最好的想法是如此, 远远是基本上使用状态monad来跟踪迭代器的当前 位置。有更清洁的方法吗?在Haskell中实现窥视迭代器
(我张贴这对初学者@过,但没有得到任何答案)
我将一些代码移植到了广泛使用 peeking迭代器的概念的Haskell中。它基本上包装了一个集合,并提供了两个“下一个”和“窥视”功能。 “next”函数使迭代器前进 并返回head元素,而“peek”函数 返回head元素而不前进迭代器。什么是 一个优雅的方式来将这个概念转化为Haskell?我最好的想法是如此, 远远是基本上使用状态monad来跟踪迭代器的当前 位置。有更清洁的方法吗?在Haskell中实现窥视迭代器
(我张贴这对初学者@过,但没有得到任何答案)
一个副作用的迭代器的想法是对立的Haskell的方式。你当然可以掀起一个monad,但那时你用Haskell(引用Simon PJ)这个世界上最好的命令式语言。
不知道更多关于你正在试图端口的代码,我不能给出非常具体的建议,但这里是我的总体思路:
使用某种倍的实现你的迭代。
您传递给折叠操作的函数应该是,其他函数由组成。可能是零或多个“偷看”操作加上一个“nexting”操作的组合。
如果你希望折叠型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的常规旧内置单链表。也许甚至是zipper。
你可以做的正是你在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)
当然Iterator
没有改变,它有回馈的一个新的版本(非常类似于随机数发生器),但我认为“可变”的东西在这里会过度。
这就是说,我认为你应该使用更多的惯用方法来做你想在Haskell中做的事情。也许你应该看看Reader
monad是如何工作的:http://learnyouahaskell.com/for-a-few-monads-more#reader
你看过Data.Enumerator包吗?它带有一个偷看功能http://hackage.haskell.org/packages/archive/enumerator/0.4.16/doc/html/Data-Enumerator.html –
@ErikHinton - 对于问题描述,枚举器可能极端矫枉过正。 –