В вашем коде есть ошибки. Тонкая настройка неправильного использования (:)
заставляет его пройти проверку типов:
separa a xs
| length xs >= a = go a (drop a xs) [take a xs]
| otherwise = [xs]
where
go a xs yss
| length xs >= a = go a (drop a xs) (yss ++ [take a xs])
-- was: (yss : (take a xs))
| otherwise = go a [] (yss ++ [xs])
-- was: (yss : xs)
go a [] yss = yss
но лучше изменить его на
separa :: Int -> [a] -> [[a]]
separa a xs
| length xs >= a = go a (drop a xs) [take a xs]
| otherwise = [xs]
where
go a xs yss
| length xs >= a = go a (drop a xs) ([take a xs] ++ yss)
| otherwise = reverse ([xs] ++ yss)
Работает:
> separa 3 [1..10]
[[1,2,3],[4,5,6],[7,8,9],[10]]
Это обычная идиома «построение в обратном порядке, затем обратное построение», часто встречающаяся в строгих функциональных языках. Некоторые из них допускают построение списков в естественном порядке сверху вниз по методике, известной как tail-recursion modulo cons . Haskell ленив и позволяет нам создавать его списки естественным и простым способом сверху вниз с помощью эквивалентной защищенной рекурсии :
separa :: Int -> [a] -> [[a]]
separa a xs
| length xs >= a = go a (drop a xs) [take a xs]
| otherwise = [xs]
where
go a xs yss
| length xs >= a = -- go a (drop a xs) (yss ++ [take a xs])
yss ++ go a (drop a xs) [take a xs]
| otherwise = -- go a [] (yss ++ [xs])
yss ++ [xs]
Здесь есть ошибка, одна за другой; Я оставлю это для вас, чтобы исправить самостоятельно.
Но иногда бесконечному типу присуща проблема, а не результат ошибки программирования. Затем мы можем исправить это с помощью рекурсивных типов.
Всякий раз, когда мы получаем эквивалентность типа t ~ a..b..t..c..
, мы можем начать с определения типа
newtype T = MkT (a..b..T..c..)
затем посмотрите, какие переменные типа свободны, и закройте их, как
newtype T a b c = MkT (a..b..(T a b c)..c..)
Пример: Ошибка бесконечного типа при определении zip только с помощью foldr; это можно исправить?