Почему этот код Haskell создает ошибку "бесконечного типа"?


Я новичок в Haskell и сталкиваюсь с ошибкой" не могу построить бесконечный тип", которую я не могу понять.

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

вот код:

intersperse :: a -> [[a]] -> [a]

-- intersperse '*' ["foo","bar","baz","quux"] 
--  should produce the following:
--  "foo*bar*baz*quux"

-- intersperse -99 [ [1,2,3],[4,5,6],[7,8,9]]
--  should produce the following:
--  [1,2,3,-99,4,5,6,-99,7,8,9]

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:y:xs) = x:s:y:intersperse s xs

и вот ошибка при попытке загрузить его в переводчик:

Prelude> :load ./chapter.3.ending.real.world.haskell.exercises.hs
[1 of 1] Compiling Main (chapter.3.ending.real.world.haskell.exercises.hs, interpreted )

chapter.3.ending.real.world.haskell.exercises.hs:147:0:
Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `intersperse'
Failed, modules loaded: none.

спасибо.

--

вот некоторые исправленные код и общее руководство для борьбы с ошибкой "бесконечного типа" в Haskell:

исправленный код

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) =  x ++ s:intersperse s xs 

в чем проблема была:

подпись моего типа утверждает, что второй параметр для intersperse-это список списков. Поэтому, когда я сопоставил шаблон с "s (x:y:xs)", x и y стали списки. И все же я рассматривал x и y как элементы, а не списки.

руководство по работе с ошибкой "бесконечного типа":

большую часть времени, когда вы получаете эту ошибку, вы забыли типы различных переменных, с которыми вы имеете дело, и вы попытались использовать переменную, как если бы это был какой-то другой тип, чем то, что он есть. Посмотрите внимательно на то, какой тип все это по сравнению с тем, как вы его используете, и это обычно будет раскрыть проблему.

4 64

4 ответа:

проблема заключается в последнем предложении, где вы рассматриваете x и y как элементы, в то время как они являются списками. Это будет работать:

intersperse _ [] = []
intersperse _ [x] = x 
intersperse s (x:y:xs) = x ++ [s] ++ y ++ intersperse s xs

ошибка бесконечного типа возникает потому, что оператор : имеет тип a -> [a] -> [a], в то время как вы рассматриваете его как [a] -> a -> [A], что означает, что [a] должен быть идентифицирован с a, что означало бы, что a является бесконечно вложенным списком. Это не допускается (и не то, что вы имеете в виду, во всяком случае).

Edit: есть также еще одна ошибка в приведенном выше код. Это должно быть:

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) = x ++ [s] ++ intersperse s xs

часто добавление явного определения типа может сделать сообщение об ошибке типа компилятора более разумным. Но в этом случае явная типизация делает сообщение об ошибке компилятора хуже.

посмотрите, что происходит, когда я позволяю ghc угадать тип intersperse:

Occurs check: cannot construct the infinite type: a = [a]
  Expected type: [a] -> [[a]] -> [[a]]
  Inferred type: [a] -> [[a]] -> [a]
In the second argument of `(:)', namely `intersperse s xs'
In the second argument of `(:)', namely `y : intersperse s xs'

, что явно указывает на ошибку в коде. Используя эту технику, вам не нужно смотреть на все и думать о типах, как предлагали другие.

Я могу ошибаться, но, похоже, вы пытаетесь решить более сложную проблему. Ваша версия intersperse не просто перемежает значение с массивом, но и выравнивает его на один уровень.

The List модуль в Haskell фактически обеспечивает функцию intersperse. Он помещает значение, заданное между элемент в списке. Например:

intersperse 11 [1, 3, 5, 7, 9] = [1, 11, 3, 11, 5, 11, 7, 11, 9]
intersperse "*" ["foo","bar","baz","quux"] = ["foo", "*", "bar", "*", "baz", "*", "quux"]

Я предполагаю, что это то, что вы хотите сделать, потому что это то, что мой профессор хотел, чтобы мы сделали, когда Я учился у Хаскелла. Конечно, я мог бы полностью отключиться.

также я нашел этой что объясняет смысл ошибки.

каждый раз, когда интерпретатор/компилятор дает мне эту ошибку, это потому, что я использую какой-то тип-параметризованный Кортеж в качестве формального параметра. Все правильно удаление определение типа функции, которая содержала переменные типа.

Я все еще не могу понять, как исправить это и сохранить определение типа функции.