2011-12-11 119 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