#list #haskell #nested-lists
#Список #haskell #вложенные списки
Вопрос:
Я очень новичок в Haskell, только начинаю его изучать. Для начала я использую учебное пособие «Изучите Хаскелл для великого блага!» и увидел пример решения проблемы «3n 1»:
chain :: (Integral a) => a -> [a]
chain 1 = [1]
chain n
| even n = n:chain (n `div` 2)
| odd n = n:chain (n*3 1)
numLongChains :: Int
numLongChains = length (filter isLong (map chain [1..100]))
where isLong xs = length xs > 15
итак, numLongChains подсчитывает все цепочки длиной более 15 шагов для всех чисел от 1 до 100.
Теперь я хочу свой собственный:
numLongChains' :: [Int]
numLongChains' = filter isLong (map chain [1..100])
where isLong xs = length xs > 15
итак, теперь я хочу не считать эти цепочки, а возвращать отфильтрованный список с этими цепочками.
Но теперь я получаю ошибку при компиляции:
Couldn't match expected type `Int' with actual type `[a0]' Expected type: Int -> Bool Actual type: [a0] -> Bool In the first argument of `filter', namely `isLong' In the expression: filter isLong (map chain [1 .. 100])
В чем может быть проблема?
Ответ №1:
Сигнатура типа numLongChains
, вероятно, неверна. В зависимости от того, что вы хотите сделать, требуется одно из следующих действий:
- Вы просто хотите посчитать эти цепочки, ваша функция
numLongChains
, очевидно, должна вернуть число, изменить первую строку наlength $ filter isLong (map chain [1..100])
и тип наInt
- Вы хотите вернуть список длин длинных цепочек. В этом случае сигнатура типа в порядке, но вам нужно вернуть длину. Я бы посоветовал вам рассчитать длину перед фильтрацией и отфильтровать ее. Тело функции становится
filter (>15) (map (length . chain) [1..100])
. - Вы хотите вернуть все цепочки, длина которых превышает 15 символов. Просто измените подпись на
[[Int]]
(список цепочек (списков) изInt
s), и все в порядке.
Комментарии:
1. Спасибо! На самом деле это моя ошибка, использование [[Int]] решило проблему
Ответ №2:
FUZxxl прав. Вы захотите изменить сигнатуру типа вашей функции на [[Int]]
. Поскольку вы фильтруете список списков и выбираете только те, которые являются достаточно длинными, вы вернете списки списков.
Одно замечание о чтении отладчика / ошибок времени компиляции Haskell. Эта ошибка может показаться странной. В нем говорится, что у вас было [a0] -> Bool
, но вы ожидали Int -> Bool
. Это связано с тем, что проверка типов предполагает, что из подписи вашей функции numLongChains вам понадобится функция фильтра, которая проверяет целые числа и возвращает список допустимых. Единственный способ отфильтровать список и получить [Int] обратно — это иметь функцию, которая принимает Int
s и возвращает Bool
s (Int -> Bool)
. Вместо этого он видит функцию, которая проверяет длину. Длина принимает список, поэтому он предполагает, что вы написали функцию, которая проверяет списки. ([a0] -> Bool)
. Иногда средство проверки не так дружелюбно, как хотелось бы, но если вы посмотрите достаточно внимательно, вы увидите, что в 9 случаях из 10 трудно расшифруемая ошибка является результатом таких предположений.
Комментарии:
1. Эрик, тебе тоже спасибо, но все, что я понимаю, это то, что мне сейчас слишком сложно 🙂 А о вредности неявного преобразования я знал из императивных языков