Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: foldr vs foldr1

Tags:

haskell

fold

If I have this insert function:

insert x []     = [x]
insert x (h:t)
  | x <= h      = x:(h:t)
  | otherwise   = h:(insert x t)

this produces a sorted list:

foldr insert [] [1,19,-2,7,43]

but this:

foldr1 insert [1,19,-2,7,43]

produces 'cannot construct the infinite type: a0 = [a0]'

I'm confused about why the second call cannot work.

I have looked at the definitions for both foldr and foldr1 and have traced both with simple arithmetic functions, but I still cannot come up with a clear explanation for why the second call fails.

like image 778
minus Avatar asked Dec 08 '12 21:12

minus


2 Answers

Let's look at some type signatures.

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

In both cases, the first argument is a function of two arguments.

  • for foldr1, these two arguments must have the same type (and the result has this type also)
  • for foldr, these two arguments may have different types (and the result has the same type as the second argument)

What's the type of your insert?

like image 86
dave4420 Avatar answered Oct 09 '22 22:10

dave4420


I like the type-based answers given here, but I also want to give an operational one explaining why we don't want this to typecheck. Let's take the source of foldr1 to start with:

foldr1          :: (a -> a -> a) -> [a] -> a
foldr1 _ [x]    = x
foldr1 f (x:xs) = f x (foldr1 f xs)

Now, let's try running your program.

foldr1 insert [1,19,-2,7,43]
= { list syntax }
foldr1 insert (1:[19,-2,7,43])
= { definition of foldr1 }
insert 1 (foldr1 insert [19,-2,7,43])
= { three copies of the above two steps }
insert 1 (insert 19 (insert (-2) (insert 7 (foldr1 insert [43]))))
= { definition of foldr1 }
insert 1 (insert 19 (insert (-2) (insert 7 43)))

...whoops! That insert 7 43 is never going to work. =)

like image 27
Daniel Wagner Avatar answered Oct 10 '22 00:10

Daniel Wagner