Почему возникает ошибка для третьего оператора ввода?

#haskell

#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 :: forall a. (Num a, Num [a]) => a
В выражении: пусть x : y = 3 : 4 в x * x y * y
В уравнении для `it’: it = пусть x : y = 3 : 4 в x * x y * y

Может кто-нибудь объяснить, что происходит в первых двух операторах и почему возникает ошибка для третьего let ... in .. оператора.

Комментарии:

1. К сожалению, ошибка неясна, но причина в следующем: : является ли оператор для построения списков с типом a -> [a] -> [a] , поэтому ему нужен список в правой части: let x:y = 3:[4] in x*x y*y . Обратите внимание, что вы не можете использовать y в качестве числовой причины

2. Спасибо за помощь! Я сам нашел ответ 🙂 Это потому, что: prepend operator добавляет что-то в список. Здесь не было списка! Это можно решить, выполнив let x:y:[] = 3:4:[] in x*x y*y OR let x:[y] = 3:[4] in x*x y*y

3. Пожалуйста, опубликуйте ответ на свой собственный вопрос и пометьте его как принятый (после некоторого времени ожидания). Именно так должен работать StackOverflow.

Ответ №1:

В третьем примере правая часть let присваивания имеет вид: 3:4 . Оператор : (cons) имеет сигнатуру типа a -> [a] -> [a] : он принимает значение в левой части и список значений этого типа в правой части. В этом случае 3 является a , но 4 не является списком a ( [a] ); это также a . Это недопустимо.

Учитывая форму вашего упражнения на данный момент, есть два способа, которыми вы можете исправить это выражение: с помощью 3:[4] или с помощью 3:4:[] .

Если бы вы попытались запустить свой код сейчас, вы бы увидели, что он завершается с ошибкой x * x y * y . Это потому, что ваше соответствие шаблону присваивает x 3 и y to [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