簡體   English   中英

Haskell 中涉及列表推導式、遞歸和刪除函數的排列

[英]Permutations in Haskell involving List Comprehensions, Recursion and the delete function

我是一個 Haskell 初學者,正在學習一本書中的練習。 第一個問題要求我定義一個函數,該函數從整數列表中刪除第一個出現的整數。

例如

delete 5 [1,5,3,5,1]

輸出:

[1,3,5,1]

第二個問題要求我創建一個函數,該函數使用我剛剛定義的刪除函數,它將整數列表作為參數,並將所有排列的列表輸出為列表。

例如

perms [1,2,3]

輸出:

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

我努力嘗試,放棄並用谷歌搜索解決方案。

這是我發現的:

perms [] = [[]]
perms xs = [ i:j | i <- xs, j <- perms $ delete i xs ]

我環顧四周,發現了許多其他類似的解決方案,幾乎相同,只是使用不同的變量名稱和括號而不是$符號,所以我猜這是慣用解決方案的常見問題。

我只是有點迷茫,試圖理解這段代碼在做什么。 我正在通過遞歸尋求逐步解釋,以了解此代碼如何創建排列列表?

就像任何對列表進行操作的遞歸函數一樣,這個遞歸函數可以分為兩種情況:

1)該函數應該在空列表上做什么?

2)如果我知道函數在長度為n的列表上做什么,我可以用它來確定函數在長度為n + 1的列表上應該做什么。

一旦你知道這兩件事,你就有了一個可以在任何列表上工作的定義(至少一個有限長度 - 這樣的過程當然永遠不會以無限長度結束;這在這里無關緊要,因為它並不重要談論無限列表中的排列很有意義)。 [如果你有任何數學背景,你會認為這是數學歸納法的一個簡單陳述。]

對於perms函數,顯然只有一種方法可以對空列表的 0 個元素進行置換:另一個空列表。 這給出了基本情況的[[]] ,如示例解決方案的第一行。

對於遞歸/歸納步驟,假設我們有一個長度為n的列表xs (其中n > 0 ),並假設(正如我們所允許的那樣)我們已經知道如何計算任何長度為n - 1列表的所有排列.

每個排列都必須從xs一個特定元素開始——讓我們稱這個元素為i ,並考慮如何獲得第一個元素是ixs的所有排列。 應該清楚的是,這些與列表delete i xs所有排列精確對應(即, delete i xs了一個i xs ) - 給定后者的排列j ,列表i : j是以i開頭的xs的排列,相反,所有這樣的xs排列都可以通過這種方式獲得。

請注意,這正是列表[ i:j | j <- perms $ delete i xs ] [ i:j | j <- perms $ delete i xs ]

(順便注意一下,因為我們假設ixs ,所以delete i xs確實有長度n - 1 ,所以通過歸納假設我們知道如何計算它。)

i當然是在那里完全任意選擇的 - 並且xs所有元素都需要被視為某些排列的第一個元素。 因此,我們簡單地將上述所有內容放在一起,對於xs所有元素i - 這正是遞歸步驟中的表達式:

[ i:j | i <- xs, j <- perms $ delete i xs ]

你可能需要慢慢地閱讀上面的一些內容,幾次,才能理解——但它基本上是非常基本的邏輯(和大多數基本邏輯一樣,有一個討厭的習慣,通常看起來比實際更復雜)。

  • 一個一個地從xs取出一個元素i
  • xs刪除i並將i附加到jxsperms的每個列表元素減去i ),直到所有i都耗盡。

暫無
暫無

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

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