2013-04-10 72 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