2012-04-11 107 views
3

我试图使用haskell删除列表中的项目的所有实例。我收到一个我不太明白的错误。任何人都可以帮助我,让我知道如果我做正确的事情?删除列表中的所有实例

deleteAllInstances :: (a, [l]) => a -> [l] -> [l] 
deleteAllInstances (a, []) = [] 
deleteAllInstances (i, (x:xs)) 
    | i == x = tail 
    | otherwise = x ++ tail 
    where tail = deleteAllInstances i xs 
+2

你会得到哪个错误? – 2012-04-11 21:27:40

回答

9

首先,类型签名的格式不正确。

deleteAllInstances :: (a, [l]) => a -> [l] -> [l] 

A型签名的形式

name :: (Constraints) => type 

其中Constraints涉及类型类,像(Ord a, Show a)。在这种情况下,该功能使用(==),因此必须有Eq a的限制。

然后函数定义与类型部分不匹配,您定义它将一对作为参数,而类型签名另有说明(您的定义不确定,类型为curried)。

deleteAllInstances (a, []) = [] 
deleteAllInstances (i, (x:xs)) 
    | i == x = tail 
    | otherwise = x ++ tail 
    where tail = deleteAllInstances i xs 

然后使用(++)一个元素胶水列表的前面,但(++)连接两个列表,你需要(:)这里。

定义函数是使用filter

deleteAllInstances :: Eq a => a -> [a] -> [a] 
deleteAllInstances a xs = filter (/= a) xs 

,但如果你想自己做明确的递归最简单的方法,

deleteAllInstances :: Eq a => a -> [a] -> [a] 
deleteAllInstances a (x:xs) 
    | a == x = rest 
    | otherwise = x : rest 
     where 
     rest = deleteAllInstances a xs 
deleteAllInstances _ _ = [] 
+0

如果我想让它也可以在字符串上工作而不仅仅是数字 – cclerville 2012-04-11 22:16:39

+5

这里没有提到数字,它适用于所有类型的'Eq'实例,包括'String','[String]'等等。它具有最普通的类型,因此它适用于可能适用的所有内容。 (你可以通过一个参数'(a - > a - > Bool)'去掉'Eq'约束,该参数说明哪些值应该被认为是'相等的';'Eq'类提供的函数类似于隐式参数) – 2012-04-11 22:25:02

+1

你说得对。谢谢! :) – cclerville 2012-04-11 23:21:50

3

我不知道你想与(a, [l])=>之前做什么,但我不认为有必要。语法通常保留用于指定a和l应该满足的类型。另外,你的函数有两个参数,a[l],正如你稍后在函数定义中指定的那样。然而,你的函数实现只需要一个参数,一个元组。正如我前面提到的,元组只能用来指定参数应该是什么类型,并且不能与模式匹配。

deleteAllInstances :: a -> [l] -> [l] 
deleteAllInstances a [] = [] 
deleteAllInstances i (x:xs) 
    | i == x = rest 
    | otherwise = x : rest 
    where rest = deleteAllInstances i xs 

如果你想使用filter写它,你总是可以使用下面的代码

deleteAllInstances :: a -> [a] -> [a] 
deleteAllInstances a = filter (/=a) 
3

其实我觉得列表理解是一个非常直观的符号表示这样的问题:

deleteAllInstances :: Eq a => a -> [a] -> [a] 
deleteAllInstances a list = [x | x <- list, x /= a] 
+0

它不是更快 - 都是'O(n)'。甚至像'filter'这样的链接多个函数仍然是'O(n)',因为_Fusion_,例如'过滤器f。地图f'。过滤器f''仍然是'O(n)'。 – 2013-06-16 08:45:34

+0

复杂性显然是相同的,但据我了解ghc,编译后的代码会更快,因为列表解析被解析为纯粹的递归,因此您将调用保存到过滤器。它可能取决于约束的复杂性。 – thrau 2013-06-16 14:06:46

+2

实际上,列表解析只是一个替代的符号语法,因此,如果一个'/ = a'然后返回一个'else []',你的理解首先解析为'list >> = \ a' - >。在那之后,优化器确实做了平移递归的转换,但是它对所生成的函数执行了这个操作,并且它会对任何受_Fusion_影响的其他函数执行。 'filter'和'map'也受到融合,这就是为什么生成的编译器代码应该与你的相同。你可以试验__ghc-core__ util,你会惊讶于优化器实际上可以做什么。 – 2013-06-16 14:24:45