如何修复代码中的错误(“无法构造无限类型”)以及如何使代码正常工作

时间:2019-01-07 12:48:07

标签: list haskell

基本上我正在尝试执行一个函数,在该函数中给您一个列表和一个数字,并且您必须将列表拆分成与给定数字大小相同的列表,并且所有最后一次拆分的长度都可以小于给出的数字

b

我希望3个“ comovais”的输出为[“ com”,“ ova”,“ is”],但是由于错误,在我的程序中没有输出

2 个答案:

答案 0 :(得分:6)

请注意表达式:

yss : (take a xs)

(take a xs)的类型为[b],因此yss的类型为b。但是,当您将yss : (take a xs)作为参数传递给separaM函数时,预期yss的类型为[b]而不是b。这就是发生错误的原因。

实际上,您不需要yss来存储结果,可以将递归函数定义为:

separaM _ [] = []
separaM a xs = (if length xs >= a then (take a xs) else xs) : 
               separaM a (drop a xs)

答案 1 :(得分:3)

Your code has some errors in it. Tweaking your misuse of (:) gets it to pass the type-checker:

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

but it's better to further change it to

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)

It works:

> separa 3 [1..10]
[[1,2,3],[4,5,6],[7,8,9],[10]]

This is a common "build in reverse, then reverse when built" idiom, frequently seen in strict functional languages. Some of them allow for lists to be built in top-down, natural order, by a technique known as tail-recursion modulo cons. Haskell is lazy, and lets us build its lists in top-down manner naturally and easily, with the equivalent guarded recursion:

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]

There's an off-by-one error here; I'll leave it for you to fix on your own.


But sometimes the infinite type is inherent to a problem, and not a result of a programming error. Then we can fix it by using recursive types.

Whenever we get type equivalency t ~ a..b..t..c.., we can start by defining a type

newtype T = MkT (a..b..T..c..)

then see which type variables are free and close over them, as

newtype T a b c = MkT (a..b..(T a b c)..c..)

An example: Infinite type error when defining zip with foldr only; can it be fixed?