拉鍊很棒,並且有一個有趣的博客文章 實施Conway's Game of Life using zippers and comonads in Haskell。在另一個 的手上,如果這仍然是你第一週學習Haskell,你可能想要在週四保存Comonads吧?
這是另一種使用簡單遞歸和列表 理解並且沒有複雜的Haskell功能的方法。
首先,假設我們有一個真棒功能:
varyOne :: (a -> [a]) -> [a] -> [[a]]
varyOne = undefined
的作品如下。給定一個函數f
產生零個或 更多的元素a
的變型,函數調用varyOne f xs
生成列表xs
,從服用導致的所有變體 正好xs
一個元素,說x
在列表的中間,和更換它與f x
給出的所有 變體。
此功能令人驚訝地靈活。它可以產生從由恆定強制替換元件產生的所有變體的列表:
> varyOne (\x -> [3]) [1,2,3,4]
[[3,2,3,4],[1,3,3,4],[1,2,3,4],[1,2,3,3]]
通過爲一個特定的值和變體的其他值的空列表返回一個單變體中,它可以生成所有的變體與'i'
替換'o'
同時抑制「變體」,其中沒有更換是可能的:
> let varyRow = varyOne (\c -> if c == 'o' then ['i'] else [])
> varyRow "ooxo"
["ioxo","oixo","ooxi"]
和,因爲varyRow
本身產生行的變體,它可以用varyOne
可以用於產生表,其中一個特定的變體行已取代其可能的變體:
> varyOne varyRow ["ooo","oox","ooo"]
[["ioo","oox","ooo"],["oio","oox","ooo"],["ooi","oox","ooo"],
["ooo","iox","ooo"],["ooo","oix","ooo"],
["ooo","oox","ioo"],["ooo","oox","oio"],["ooo","oox","ooi"]]
事實證明,這真棒功能是非常容易寫:
varyOne :: (a -> [a]) -> [a] -> [[a]]
varyOne f (x:xs)
= [y:xs | y <- f x] ++ [x:ys | ys <- varyOne f xs]
varyOne _ [] = []
第一個列表理解產生當前元素的所有變種。第二個列表理解生成的變體涉及使用遞歸調用varyOne
更改當前元素的權限。
鑑於varyOne
,我們可以這樣定義:
replaceOne :: Char -> Char -> Mappy -> [Mappy]
replaceOne old new = varyOne (varyOne rep1)
where rep1 x = if x == old then [new] else []
和:
> replaceOne 'o' 'i' ["ooo","oox","ooo"]
[["ioo","oox","ooo"],["oio","oox","ooo"],["ooi","oox","ooo"]
,["ooo","iox","ooo"],["ooo","oix","ooo"]
,["ooo","oox","ioo"],["ooo","oox","oio"],["ooo","oox","ooi"]]
可能是你正在尋找的功能。
如果你願意無條件與i
更換一個單一的元素,不管是什麼老的因素是,那麼這將工作:
> varyOne (varyOne (const ['i'])) ["ooo","oox","ooo"]
[["ioo","oox","ooo"],["oio","oox","ooo"],["ooi","oox","ooo"]
,["ooo","iox","ooo"],["ooo","oix","ooo"],["ooo","ooi","ooo"]
,["ooo","oox","ioo"],["ooo","oox","oio"],["ooo","oox","ooi"]]
你應該改變只比不確定... –
我多很多不要以爲你在正確的軌道上。我試着從寫一個函數開始,在給定一行的情況下,計算所有可能的變體行的列表。 – chi
嗨,@BaasBartMans。歡迎來到Stack Overflow。我認爲這是一個很好的問題,但它有被關閉的危險。我試圖重寫它以使其更清晰。如果您認爲我誤解了您所問的內容,請隨時對其進行編輯(或更改內容)。 –