2014-12-10 140 views
2

我开始使用the University of Pennsylvania's free online course materials来学习Haskell。这些都是故意上网的,所以我想通过问这个问题我没有帮助任何人的功课。模式匹配Haskell列表

我从下面的函数中得到一些编译器错误,我用它来回答第一个任务的一部分,但我找不出原因。我的作用是:

doubleEveryOther :: [Integer] -> [Integer] 
doubleEveryOther [] = [] 
doubleEveryOther [x] = [x] 
doubleEveryOther [x:y] = [x:(y*2)] 
doubleEveryOther [x:y:ys] = [x:y*2:doubleEveryOther ys] 

我得到的是这些错误:

01.hs:18:19: 
    Couldn't match expected type ‘Integer’ with actual type ‘[a0]’ 
    In the pattern: x : y 
    In the pattern: [x : y] 
    In an equation for ‘doubleEveryOther’: 
     doubleEveryOther [x : y] = [x : (y * 2)] 

01.hs:18:27: 
    Couldn't match expected type ‘Integer’ with actual type ‘[a0]’ 
    Relevant bindings include 
     y :: [a0] (bound at 01.hs:18:21) 
     x :: a0 (bound at 01.hs:18:19) 
    In the expression: x : (y * 2) 
    In the expression: [x : (y * 2)] 
    In an equation for ‘doubleEveryOther’: 
     doubleEveryOther [x : y] = [x : (y * 2)] 

01.hs:19:19: 
    Couldn't match expected type ‘Integer’ with actual type ‘[Integer]’ 
    In the pattern: x : y : ys 
    In the pattern: [x : y : ys] 
    In an equation for ‘doubleEveryOther’: 
     doubleEveryOther [x : y : ys] = [x : y * 2 : doubleEveryOther ys] 

01.hs:19:30: 
    Couldn't match expected type ‘Integer’ with actual type ‘[Integer]’ 
    In the expression: x : y * 2 : doubleEveryOther ys 
    In the expression: [x : y * 2 : doubleEveryOther ys] 
    In an equation for ‘doubleEveryOther’: 
     doubleEveryOther [x : y : ys] = [x : y * 2 : doubleEveryOther ys] 

谁能帮助我了解为什么我的模式不匹配正确的类型?

+0

过了一个完整的答案累了,对不起,但下面可能会给你一个想法:'[X,Y]','(X:Y :YS)'。 – Zeta 2014-12-10 22:01:02

回答

3

问题很简单:[]表示元素列表。并且:表示加入一个元素和一个列表。所以[x:ys]实际上意味着[[x,y1,y2..]] - 注意双括号。所以这是您的案例列表Integer列表,而不是Integer列表。

doubleEveryOther :: [Integer] -> [Integer] 
doubleEveryOther [] = [] 
doubleEveryOther [x]= [x] 
doubleEveryOther [x,y] = [x, y*2] 
doubleEveryOther (x:y:ys) = x : y*2 : doubleEveryOther ys 

如果希望所有4个方程式中使用相同的语法,那么你就不能使用[],因为它不允许ys,所以你必须使用:无处不在:

doubleEveryOther :: [Integer] -> [Integer] 
doubleEveryOther [] = [] 
doubleEveryOther (x:[])= x:[] 
doubleEveryOther (x:y:[]) = x : y*2 : [] 
doubleEveryOther (x:y:ys) = x : y*2 : doubleEveryOther ys 
+0

*'[x:ys]'实际上是指'[[x,y1,y2 ..]] *。这不是100%准确。在'[x:ys]'的模式中,'ys'可以为零,在这种情况下不存在'y1'和'y2'。 – Jubobs 2014-12-10 22:25:30

+0

好的,谢谢,现在我明白了。 – 2014-12-10 22:26:53

2

的代码应该是:

doubleEveryOther :: [Integer] -> [Integer] 
doubleEveryOther [] = [] 
doubleEveryOther [x] = [x] 
doubleEveryOther (x:y:[]) = [x, (y*2)] 
doubleEveryOther (x:y:ys) = x: y*2 : doubleEveryOther ys 

您可以直接在列表上没有模式匹配,因为列表语法只是语法糖。必须匹配函数调用(具体调用(:),cons运算符)。而这些比赛需要用括号括起来。

而且你没有用括号括起反对号召。 [1 : 2 : []][[1, 2]]相同。为了使它更清晰一些,在你的代码中你有[x : y*2]xy都是Int s。但是缺点(:)(:) :: a -> [a] -> [a]的类型。你用两个Int s,而不是Int[Int]来调用它。

+1

'[x]'是一个单身人士名单的有效模式,虽然;它不一定是'(x:[])'。加里说得对。 – Jubobs 2014-12-10 22:14:18

+1

不知道。我编辑了我的答案。 – 2014-12-10 22:15:45

+0

谢谢,解决了它。你能否详细说明为什么你的最终模式匹配能够起作用,但是在倒数第二场比赛中使用cons运算符却不行?我想确保我真的明白这一点。 – 2014-12-10 22:19:43

1

在此外,您的第3行是4号线的一部分,所以

doubleEveryOther :: [Integer] -> [Integer] 
doubleEveryOther [] = [] 
doubleEveryOther [x]= [x] 
doubleEveryOther (x:y:ys) = x : y*2 : doubleEveryOther ys