In chapter 6 of Learn You a Haskell, the following function is introduced:
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' _ [] _ = []
zipWith' _ _ [] = []
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys
The author gives a couple examples of its use which I found easy enough to follow. Then this one:
ghci> zipWith' (zipWith' (*)) [[1,2,3],[3,5,6],[2,3,4]] [[3,2,2],[3,4,5],[5,4,3]]
Which outputs [[3,4,6],[9,20,30],[10,12,12]]
Is this an example of lazy evaluation? I tried to translate zipWith' into Scheme (see below). I got it working with the "easy" examples, but not the last one, which makes me think that Haskell's laziness might be making the difference.
(define zipWith
(lambda (f listA listB)
(cond
((null? listA) (quote ()))
((null? listB) (quote ()))
(else (cons (f (car listA) (car listB)) (zipWith f (cdr listA) (cdr listB)))))))
No, although this example will be evaluated lazily (like any other function in Haskell), the behaviour doesn't depend on that. On finite lists it would behave the same way with eager evaluation. On infinite lists, of course, it would never terminate with eager evaluation, but lazy evaluation allows you to evaluate only as many list elements as you need.
If you post the code you're using to call the Scheme zipWith for the last example, maybe we can help see why that's behaving differently.
zipWith' (*) [1,2,3] [1..]
would (have use of) evaluate lazily
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With