2013-04-10 69 views
4

我怎麼能寫在Haskell一個函數,它接受一個列表和一個數字,它會刪除所有的比數較大的元素,並返回列表。如何寫一個遞歸函數在Haskell

刪除[5,4,3,9,1] 5應返回[5,4,3,1]

我寫了下面方法,它正在成爲無限循環一些當它擊中比大於其中給定的數字。我正在走出[5,4,3,然後程序沒有結束。

remove l1 x = if (null l1 == True) 
       then l1 
       else if (head l1 > x) 
         then remove (drop 0 l1) x 
         else ((head l1) : remove (tail l1) x) 

這是我第一次嘗試Haskell程序,請告訴我我在做什麼錯在這裏。

感謝

+4

你得到了無限循環,因爲'然後刪除(drop 0 l1)x'你在同一個列表上重複出現,'drop'的第一個參數表示要刪除多少個元素,並且您錯誤地輸入了'drop 0'而不是你需要「降1」。 – 2013-04-10 10:20:17

回答

7

您可以使用模式在函數參數匹配,並與警衛過濾:

remove [] x = [] 
remove (h:t) x | h > x = remove t x 
       | otherwise = h : remove t x 

你也可以使用功能filter,它做你的需要:

remove l x = filter (<= x) l 
12

好,你的體面的開始,但重要的是要注意,你沒有采取最「Haskell」的方法。

讓我告訴你一些不同的方法解決這個問題:

方法1:遞歸函數

首先,我們可以寫一個遞歸函數(如你)來解決這個。

要做到這一點,我們首先容納用於一個基本情況(一個不會,一般情況下,允許一個無限循環)。這應該工作:

remove [] _ = [] 

這僅僅是說,如果我們從一個空的列表中刪除元素,我們結束了一個空列表。就這麼簡單。 _意味着我們不在乎x是什麼值。現在

我們必須定義其他案件。對於這一點,我會用後衛(我敢肯定有其他的辦法,基本情況還增加了完成):

remove [] _ = [] 
remove (x:xs) y 
| x > y  = remove xs y 
| otherwise = x : remove xs y 

所以,第一行(remove (x:xs) y)是說,我們的函數將採取列表(其中x是磁​​頭/第一值和xs是其餘部分)。

第二行是說,如果x大於y,請考慮其餘元素,並且我們不認爲x是我們最終解決方案的一部分。

第三行(otherwise捕獲所有的情況下,如果命中,就像if/elseif/elseif/elseif/else其他語言的條件塊中的else)。如果我們到了這一點,我們知道這是不正確的x > y所以我們認爲我們的價值觀(xs)的其餘部分,我們包括x,但我們與x做了現在。

現在,這種方法工作體面,但有一個簡單的辦法:

方法2:列表綜合

使用list comprehensions我們可以建立一個非常簡單的,功能強大的解決方案:

remove xs y = [x | x <- xs, not (x > y)] 

如果你曾經學過set-theory(特別是set-builder notation),你應該看起來很奇怪。我們來看看每個部分的含義。

  • [...] - 東西方括號只是意味着我們正在建設一個列表

  • x |... - 意味着我們的列表將包含x S,從而使(該|手段 「使得」)...

  • x <- xs, - xxs(逗號表示 「和」)的元素,...

  • not (y > x) - 這是不正確的y大於x

正如你所看到的,第二種方法幾乎完全模仿你的問題的描述。這確實是Haskell的力量,單詞和抽象幾乎都直接映射到Haskell代碼中。

方法3:使用filter

由於下面的評論的狀態的第三替代方案將是把它定義爲這樣:

remove y = filter (<=y) 

當過濾器將只保留是小於或等於的元素到y。 (感謝Daniel Wagner提供這種方法)。

+4

...或者只是'刪除y = filter(<= y)'。 – 2013-04-10 12:04:40

+0

是的,好點。我看到另一個答案,並給他們+1。 – mjgpy3 2013-04-10 13:28:01