[Haskell-cafe] Exercise in YAHT
Daniel Fischer
daniel.is.fischer at web.de
Sun Aug 6 08:30:21 EDT 2006
Am Sonntag, 6. August 2006 11:50 schrieb algorithms at gmx.de:
> Dear Hugs users,
>
> could you answer the following question from a Haskell novice?
>
> In "Yet another Haskell Tutorial" by Hal Daumé III there is the following
> exercise:
>
> Exercise 4.8 Write functions listHead, listTail, listFoldl and listFoldr
> which are equivalent to their Prelude twins, but function on our List
> datatype. Don’t worry about exceptional conditions on the first two.
>
> My question is solely on listfoldr, in fact I only want to ask whether the
> solution provided in the tutorial is really so obviously wrong as I
> perceive it to be:
>
> (What follows uses the definition
>
> data List a = Nil
>
> | Cons a (List a)
>
> )
>
>
>
> listFoldr f y Nil = y
> listFoldr f y (Cons x xs) = f x (foldr f z xs)
>
>
> This IS wrong, isn't it? The y does not even appear after all.
Yes, definitely wrong. Obviously Hal was tired when this slipped past his
eyes. The "z" should be "y" and of course he can't use foldr here, he meant
listFoldr (and typed foldr out of habit, probably).
So:
listFoldr f y Nil = y
listFoldr f y (Cons x xs) = f x (listFoldr f y xs)
>
> And what can you say about my attempt
> for listFoldr?
>
> listFoldr f y Nil = y
> listFoldr f y (Cons x xs) = f y (listFoldr f (f y x) xs)
>
You should apply f only once to x, this way you fold in f from the left and
from the right, so you get different results:
foldLR f y [] = y
foldLR f y (x:xs) = f x (foldLR f (f x y) xs)
-- I changed the argument order of the inner application of f, so foldLR has
the same type as foldr
Prelude> :t foldLR
foldLR :: (a -> t -> t) -> t -> [a] -> t
Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
Prelude> foldLR (+) 0 [1 .. 10]
110
Prelude> foldLR (*) 1 [1 .. 6]
518400
Prelude> foldr (:) [] [1 .. 10]
[1,2,3,4,5,6,7,8,9,10]
Prelude> foldLR (:) [] [1 .. 10]
[1,2,3,4,5,6,7,8,9,10,10,9,8,7,6,5,4,3,2,1]
you see what's going on, don't you?
>
> My attempt yields a similar, albeit not identical result compared with the
> Prelude function foldr when :t-ing it under Hugs:
>
> Hugs> :t foldr
> foldr :: (a -> b -> b) -> b -> [a] -> b
>
> Hugs> :t listFoldr
> listFoldr :: (a -> a -> a) -> a -> List a -> a
>
That's because of the (f y x) in your definition, let's do some type
inference:
1) listFoldr f y Nil = y
so listFoldr takes three arguments,
f - whose type we know nothing about yet and call tf for the moment
y - the type of which we also don't know and call ty
a third argument, which may be Nil and so has type List tl for some - as yet
completely arbitrary type tlist
and returns the second of its arguments, so from the first equation we find
listFoldr :: tf -> ty -> List tlist -> ty
2) listFoldr f y (Cons x xs) = f x (listFoldr f (f y x) xs)
here we see that f is applied to two arguments (twice), hence has type
ta1 -> ta2 -> tres, so we found out more about tf.
Now in the outer application of f, the first argument of f is x, of type
tlist, the second argument is a result of listFoldr, hence of type ty and the
result of this application of f is the overall result of listFoldr, hence has
type ty as we know from above, so
ta1 = tlist
ta2 = ty
tres = ty, yielding
tf = tlist -> ty -> ty
and
listFoldr :: (tlist -> ty -> ty) -> ty -> List tlist -> ty
which we'd want, but we have a further application of f, which might provide
further information, namely f y x
Now we know f's type
tlist -> ty -> ty,
so we deduce
y :: tlist
x :: ty,
which together with y :: ty yields tlist = ty, hence
listFoldr :: (ty -> ty -> ty) -> ty -> List ty -> ty
and now rename ty as a.
>
> Thank you very much.
>
> Christian
HTH,
Daniel
--
"In My Egotistical Opinion, most people's C programs should be
indented six feet downward and covered with dirt."
-- Blair P. Houghton
More information about the Haskell-Cafe
mailing list