Question

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)))))))
Was it helpful?

Solution 3

jberryman's link in a comment to my original post provides the most comprehensive answer. Thanks to all who replied.

(edit-in: as @newacct mentions in the comments, partial application is trivially achieved with explicit lambda construction, (lambda (x y) (zipWith * x y)). Lambdas are very basic in Scheme, we don't need macros for that.)

OTHER TIPS

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top