为什么第三个让入语句出错?

时间:2019-03-18 08:43:41

标签: haskell

Prelude> let [x,y] = [3,4] in x*x+y*y

  

25

Prelude> let x:[y] = [3,4] in x*x + y*y

  

25

Prelude> let x:y = 3:4 in x*x+y*y

  

交互式:6:5:错误:
      *约束中的非类型变量参数:Num [a]
        (使用FlexibleContexts允许此操作)
      *检查推断类型时
          x ::全部(数字a,数字[a])=> a
        在表达式中:让x:y = 3:4 in x * x + y * y
        在“ it”的等式中:it = let x:y = 3:4 in x * x + y * y

有人可以解释一下前两个语句中发生了什么,为什么第三个let ... in ..语句有错误。

1 个答案:

答案 0 :(得分:6)

在第三个示例中,let分配的右侧为:3:4:(cons)运算符的类型签名为a -> [a] -> [a]:它的左侧带有一个值,右侧带有该类型的值的列表。在这种情况下,3a,但是4不是a[a])的列表;它也是a。这是无效的。

鉴于到目前为止的锻炼形式,有两种方法可以解决此问题:3:[4]3:4:[]

如果现在尝试运行代码,您会发现它在x * x + y * y上失败。这是因为您的模式匹配将x分配给3,并且将y分配给[4](单例列表)。列表本身不能相乘,也不能添加到数字中。因此,我们再次在左侧使用解决方案:

let x:y:[] = 3:4:[]
    in x * x + y * y

如果我们添加了太多的类型注释,则可以希望看到哪里出了问题:

-- These work fine
-- let [x, y] = [3, 4] in ...
example1 = let [(x :: a), (y :: a)] :: [a]
             = [(3 :: a), (4 :: a)] :: [a]
            in x * x + y * y
-- let x:[y] = [3, 4] in ...
example2 = let ((x :: a) : ([(y :: a)] :: [a])) :: [a]
            in x * x + y * y

-- This is the incorrect implementation
-- let x:y = 3:4 in ...
example3 :: (Num a) => a
example3 = let (x :: a) : (y :: [a])   -- (:) :: a -> [a] -> [a]
             = (3 :: a) : (4 :: a)     -- 4 :: a is invalid here: require [a]
            in (x :: a) * (x :: a)
             + (y :: [a]) * (y :: [a]) -- Trying to multiply two lists

-- This is the fixed implementation
-- let x:y:[] = 3:4:[] in ...
example3' :: (Num a) => a
example3' = let ((x :: a) : (y :: a) : ([] :: [a])) :: [a]
              = ((3 :: a) : (4 :: a) : ([] :: [a])) :: [a]
             in x * x + y * y