我將一些代碼移植到了廣泛使用 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 - 對於問題描述,枚舉器可能極端矯枉過正。 –