简体   繁体   中英

Haskell error using foldr

I am new to haskell and trying out some exercises

I dont understand whats the error generated and why it is generated

split = foldr 
        (\x y -> y:x)
        [[]]

the error on the interpretator is as below

    Occurs check: cannot construct the infinite type: a0 = [a0]
    In the first argument of `(:)', namely `y'
    In the expression: y : x
    In the first argument of `foldr', namely `(\ x y -> y : x)'
Failed, modules loaded: none.

anyone can help? Thanks in advance

Type of foldr is

foldr :: (a -> b -> b) -> b -> [a] -> b

so in split

split = foldr (\x y -> y:x) [[]]

y and y:x has to be of same type, which is not possible for any x and y as y:x will always be one step deeper in the list than y .

I think you wanted to do x:y ?

Recall the type of foldr : (a -> b -> b) -> b -> [a] -> b . This says that foldr expects a function that combines an element of the list with a value of the final result type, producing a new value of the result type.

For the first argument, you've given foldr the function \\xy -> y:x , where x will be the list elements and y the result of the next step to the right; and the result of applying this lambda should have the same type as y .

But the type of (:) is a -> [a] -> [a] --that is, it appends a single element to the head of a list. In the expression y:x , you're taking something of the "result" type and using it as an element of a list used as the result.

Because of that, GHC attempts to infer that the result type b is the same as the type [b] , which is then of course the same as the type [[b]] , and [[[b]]] ... and so on. Thus it complains about an "infinite type".

The posts before me answer your question, but after your comment i can see that you want a function that splits your list by a predicate.

You can use groupWith::Ord b => (a -> b) -> [a] -> [[a]] from the module GHC.Exts and supply it with a function of type (a -> Bool) in your example:

groupWith even [1,2,3,4,5,6] yields [[1,3,5],[2,4,6]]

Also, something ugly but that achieves the type of "outing" you want is:

split::Eq a => (a -> Bool) -> [a] -> [[a]]
split f ls = (ls \\ rl):rl:[]
    where rl = filter f ls

But this will always split the supplied list in just two lists because of the binary function you supply.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM