Why does foldr work in an infinite list?

This function can work on infinity join lists, and it's easy to see why:

findKey :: (Eq k) => k -> [(k,v)] -> Maybe v  
findKey key [] = Nothing  
findKey key ((k,v):xs) = if key == k  
                         then Just v  
                         else findKey key xs

      

When it finds the key, it returns Just v

, stopping the recursion. Now consider the following implementation:

 findKey' :: (Eq k) => k -> [(k,v)] -> Maybe v  
 findKey' key = foldr (\(k,v) acc -> if key == k then Just v else acc) Nothing

      

How does the compiler / interpreter know that when a key matches k, it can return it?

 *Main> findKey' 1 $ zip [1..] [1..]

      

returns Just 1

When he finds that key == k

, he returns Just v

. Why does recursion stop there, allowing us to do things like this with infinity association lists?

+3


source to share


2 answers


Since the function passed to foldr

does not always evaluate the parameter acc

, that is, it is lenin in that parameter.

For example,

(\(k,v) acc -> if 1 == k then Just v else acc) (1,"one") (error "here be dragons!")

      

will return "one"

without even trying to evaluate the expression error

.

Moreover, foldr

by definition it satisfies:

foldr f a (x:xs) = f x (foldr f a xs)

      

If it is x:xs

infinite, but f

does not use its second argument, it foldr

can return immediately.

In your example, f

evaluates its second element if and only if the first argument is not a necessary association. This means that the list of associations will only be evaluated enough to find the association key

.



If you like experimenting, try this instead:

foldr (\(k,v) acc -> case acc of
          Nothing -> if key == k then Just v else acc
          Just y  -> if key == k then Just v else acc) Nothing

      

case

looks redundant as the function returns the same on both branches. However, this requires evaluation acc

, breaking the code into infinite lists.

One more thing you can try

foldr (:) [] [0..]

      

This basically restores the infinite list as it is.

foldr (\x xs -> x*10 : xs) [] [0..]

      

This multiplies everything by 10

and is equivalent map (*10) [0..]

.

+6


source


A non-empty case foldr

can be defined as foldr f init (x:xs) = f x (foldr f init xs)

. In your case it f

is (\(k,v) acc -> if key == k then Just v else acc)

, so it (k,v)

denotes the current item in the list, and acc

denotes (foldr f init xs)

. That is, it acc

means a recursive call. In then

-case you are not using acc

, so no recursive call occurs, since Haskell is lazy, value arguments are not evaluated before (and if not used).



+2


source







All Articles