簡體   English   中英

在Haskell中生成所有可能的路徑

[英]Generating All Possible Paths in Haskell

我的措辭非常糟糕,所以請耐心等待。

我正在做一個問題,需要我在Haskell中以列表列表的形式生成所有可能的數字。

例如,如果我有x = 3和y = 2,我必須生成一個列表列表,如下所示:

[[1,1,1], [1,2,1], [2,1,1], [2,2,1], [1,1,2], [1,2,2], [2,1,2], [2,2,2]]

x和y被傳遞給函數,它必須使用任何非零正整數x和y。

我完全迷失了,不知道怎么開始。

對於任何有興趣幫助我的人,請盡量使用盡可能容易理解的數學解釋。 我真的不擅長數學。

假設這是作業,我會給你答案的一部分,並告訴你我如何通過這類問題思考。 在GHCi中進行實驗並構建我們需要的部分是有幫助的。 我們需要的一件事是能夠生成從1到y的數字列表。 假設y是7.那么:

λ> [1..7]
[1,2,3,4,5,6,7]

但正如您稍后會看到的,我們真正需要的不是一個簡單的列表,而是一個我們可以構建的列表列表。 像這樣:

λ> map (:[]) [1..7]
[[1],[2],[3],[4],[5],[6],[7]]

這基本上是指取數組中的每個元素,並將其添加到空列表[] 所以現在我們可以編寫一個函數來為我們這樣做。

makeListOfLists y = map (:[]) [1..y]

接下來,我們需要一種方法將新元素添加到列表列表中的每個元素。 像這樣的東西:

λ> map (99:) [[1],[2],[3],[4],[5],[6],[7]]
[[99,1],[99,2],[99,3],[99,4],[99,5],[99,6],[99,7]]

(我在這里用的是99而不是1,所以你可以很容易地看到數字的來源。)所以我們可以編寫一個函數來做到這一點:

prepend x yss = map (x:) yss

最終,我們希望能夠獲取列表和列表列表,並在列表中的每個元素上調用prepend列表中的每個元素。 我們可以再次使用map函數。 但事實證明,如果我們將參數的順序切換為prepend將會更容易,如下所示:

prepend2 yss x = map (x:) yss

然后我們可以這樣做:

λ>  map (prepend2 [[1],[2],[3],[4],[5],[6],[7]]) [97,98,99]
[[[97,1],[97,2],[97,3],[97,4],[97,5],[97,6],[97,7]],[[98,1],[98,2],[98,3],[98,4],[98,5],[98,6],[98,7]],[[99,1],[99,2],[99,3],[99,4],[99,5],[99,6],[99,7]]]

所以現在我們可以編寫該函數:

supermap xs yss = map (prepend2 yss) xs

使用您的示例,如果x = 2且y = 3,那么我們需要的答案是:

λ> let yss = makeListOfLists 3
λ> supermap [1..3] yss
[[[1,1],[1,2],[1,3]],[[2,1],[2,2],[2,3]],[[3,1],[3,2],[3,3]]]

(如果這就是我們所需要的全部內容,我們可以使用列表理解更輕松地完成此操作。但由於我們需要能夠為任意x執行此操作,因此列表理解不起作用。)

希望您可以從這里獲取它,並將其擴展到任意x。

對於特定的x,如前所述,列表理解可以解決問題,假設x等於3,可以編寫以下內容:

 generate y = [[a,b,c] | a<-[1..y], b<-[1..y], c <-[1..y]]

但是當x沒有預先確定時,生活變得復雜得多。 我在Haskell中沒有太多的編程經驗,我不熟悉庫函數,我的方法遠不是最有效的解決方案,所以不要過於嚴厲地判斷它。

我的解決方案包括兩個功能:

strip [] = []
strip (h:t) = h ++ strip t

populate y 2 = strip( map (\a-> map (:a:[]) [1..y]) [1..y])
populate y x = strip( map (\a-> map (:a) [1..y]) ( populate y ( x - 1) ))

strip是為嵌套列表定義的。 通過合並列表項,它可以減少層次結構。 例如打電話

strip [[1],[2],[3]]

生成輸出:

[1,2,3]

填充是棘手的。

在遞歸的最后一步,當第二個參數等於2時,函數將[1..y]的每個項目與同一列表中的每個元素映射到一個新列表中。 例如

map (\a-> map (:a:[]) [1..2]) [1..2])

生成輸出:

[[[1,1],[2,1]],[[1,2],[2,2]]]

並且條帶功能將其轉換為:

[[1,1],[2,1],[1,2],[2,2]]

至於遞歸的初始步驟,當x大於2時,populate幾乎完全相同,除了這次它將列表的項目與遞歸調用生成的列表進行映射。 最后:

populate 2 3

給我們想要的結果:

[[1,1,1],[2,1,1],[1,2,1],[2,2,1],[1,1,2],[2,1,2],[1,2,2],[2,2,2]]

正如我上面提到的,這種方法既不是最有效也不是最可讀的方法,但我認為它解決了這個問題。 實際上,理論上解決這個問題的唯一方法是在沒有大量使用遞歸的情況下構建帶有list comprehension語句的字符串,而不是動態編譯該字符串,根據我的短暫經驗,作為程序員,它永遠不會是一個好的解。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM