2011-12-11 60 views
2

我将一些代码移植到了广泛使用 peeking迭代器的概念的Haskell中。它基本上包装了一个集合,并提供了两个“下一个”和“窥视”功能。 “next”函数使迭代器前进 并返回head元素,而“peek”函数 返回head元素而不前进迭代器。什么是 一个优雅的方式来将这个概念转化为Haskell?我最好的想法是如此, 远远是基本上使用状态monad来跟踪迭代器的当前 位置。有更清洁的方法吗?在Haskell中实现窥视迭代器

(我张贴这对初学者@过,但没有得到任何答案)

+1

你看过Data.Enumerator包吗?它带有一个偷看功能http://hackage.haskell.org/packages/archive/enumerator/0.4.16/doc/html/Data-Enumerator.html –

+0

@ErikHinton - 对于问题描述,枚举器可能极端矫枉过正。 –

回答

6

一个副作用的迭代器的想法是对立的Haskell的方式。你当然可以掀起一个monad,但那时你用Haskell(引用Simon PJ)这个世界上最好的命令式语言。

不知道更多关于你正在试图端口的代码,我不能给出非常具体的建议,但这里是我的总体思路:

  • 使用某种的实现你的迭代。

  • 您传递给折叠操作的函数应该是,其他函数由组成。可能是零或多个“偷看”操作加上一个“nexting”操作的组合。

如果你希望折叠型a -> b -> a的东西,你peeknext版本可能都有这种类型的,你撰写他们是这样的:

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 

你会看到,无论是peeknext参数查看相同的b,但peek将信息累积到a',然后next操作看到该信息。

你可以根据自己的喜好编写尽可能多的代码,然后将构图传递给foldl或类似的东西。

3

通常在Haskell中,不是迭代器,而是计算无限列表(通常由递归函数生成)。除了“从迭代器中获取元素”之外,您只需遍历列表(通常使用递归函数,折叠或贴图或其他东西),然后根据需要查看列表中的元素。由于Haskell是懒惰的,它只会在你需要时计算值。

我认为你应该使用递归函数来实现你的任务,该函数采用无限列表。要“偷看”,只需查看列表的第一个元素即可。 (只要索引列表,你可以根据需要“浏览”尽可能多的元素从列表的当前“头部”向下)。为了“推进”迭代器,只需递归地调用列表的尾部即可。

4
type Iterator a = [a] 

peek :: Iterator a -> a 
peek = head 

next :: Iterator a -> Iterator a 
next = tail 

你描述的声音听起来像Haskell的常规旧内置单链表。也许甚至是zipper

1

你可以做的正是你在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