Why is this recursive map function only being applied to the last two elements in the list?

半城伤御伤魂 提交于 2019-12-24 01:18:33

问题


This is the problem given: What are the first 8 elements in the following list?

mystery = 0 : 10 : (map(+1)mystery)

The answer is [0,10,1,11,2,12,3,13...]

But in my opinion the answer should be [0,10,1,11,1,11,2,12]. The following steps show why:

1) We are given ;list [0,10] so after applying the function the first time we have the list [0,10,1, 11] 2) Now we have a list [0,10,1,11] so after applying the function again the resulting list should be [0,10,1,11,1,11,2,12]

Apparently that is not the case. Can anyone explain why?


回答1:


Before diving into the definition of mystery, let's take a look at one of the laws map obeys:

map f (map g xs) == map (f . g) xs

A rather informal proof of this law is easy to follow:

map f (map g [x1, x2, ..., xn]) == map f [g x1, g x2, ..., g xn]
                                == [f (g x1), f (g x2), ..., f (g xn)]
                                == [(f.g) x1, (f.g) x2, ..., (f.g) xn]
                                == map (f.g) [x1, x2, ..., xn]

With that in mind, let's expand mystery step by step:

mystery == 0 : 10 : map (+1) mystery
        -- by definition of mystery
        == 0 : 10 : map (+1) (0 : 10 : map (+1) mystery)
        -- by definition of map and the fact that  0 + 1 == 1
        == 0 : 10 : 1 : map (+1) (10 : map (+1) mystery)
        -- by definition of map and the fact that 10 + 1 == 11
        == 0 : 10 : 1 : 11 : map (+1) (map (+1) mystery)
        -- using the law above, and the fact that (+1) . (+1) == (+2)
        == 0 : 10 : 1 : 11 : map (+2) mystery
        == 0 : 10 : 1 : 11 : map (+2) (0 : 10 : map (+1) mystery)
        == 0 : 10 : 1 : 11 : 2 : map (+2) (10 : map (+1) mystery)
        == 0 : 10 : 1 : 11 : 2 : 12 : map (+2) (map (+1) mystery)
        == 0 : 10 : 1 : 11 : 2 : 12 : map (+3) mystery
        -- etc

You don't start with a finite list [0, 10]; you start with an infinite list that begins with 0 and 10, with the remaining elements defined recursively.

In some sense, there is no closed form for the list, but that doesn't matter; laziness means that you only apply map to mystery as needed to get requested items. For example, neither head mystery nor head (tail mystery) ever need to evaluate the call to map, and head (tail (tail mystery)) only needs to map (+1) to the head mystery, not the entire infinite list.

Laziness blurs the distinction between the list and the algorithm to compute the list.




回答2:


Let's just work through it, using the recursive definition of map:

map _ [] = []
map f (x:xs) = f x : map f xs

Since we have

mystery = 0:10:(map (+1) mystery)

we already know that

mystery = [0, 10, ...]

and the ... stands for map (+1) mystery. So let's use the definition above to calculate it.

The list we're applying it to clearly isn't empty - it starts with 0 and 10. So we use the second line, with x as 0 and xs as 10:(map (+1) mystery):

map (+1) mystery = 1:(map (+1) (10:(map (+1) mystery)))

or, using the formula again for the first level of nesting:

map (+1) mystery = 1:11:(map (+1) (map (+1) mystery))

So, going back to mystery itself, we now know its first 4 elements:

mystery = [0, 10, 1, 11, ...]

and the ... stands for the contents of map (+1) (map (+1) mystery). That is, based on the result above:

map (+1) (1:11:(map (+1) (map (+1) mystery)))

I'll spare you the details of the evaluation here, because it should be clear by now what happens: the first 2 elements (which will be the 5th and 6th in mystery) will be 2 and 12, and the rest will be map (+1) ((map (+1) (map (+1) mystery))). Which, by exactly the same process, will start with 3 and 13. And so it goes on, as far as you could ever care to calculate it.




回答3:


Since

mystery = 0 : 10 : map (+1) mystery

by the definitions of (!!) and (:) and map it is the case that

mystery !! 0 = 0          -- pseudocode
mystery !! 1 = 10
mystery !! n | n > 1
             = (0 : 10 : map (+1) mystery) !! n
             = (10 : map (+1) mystery) !! (n-1)
             = (map (1+) mystery) !! (n-2)
             = 1 + (mystery !! (n-2))

and there's your answer.

An illustration:

--         0   1  2   3  4   5  6        -- n
mystery = [0, 10, 1, 11, 2, 12, 3, ...
--               /   /  /   /  /         -- (+1)
--              [0, 10, 1, 11, 2, ...
--               0   1  2   3  4         -- n-2

so all this is, is each element being defined with the reference to a previous one, two positions prior.

Thus another way to write the same thing down, making the pairing up (nay zipping) explicit, is

mystery = 0 : 10 : zipWith (+) (repeat 1)
                               mystery
-- and in general,
-- map (f y) xs  ==  zipWith f (repeat y) xs 

Translated into an imperative pseudocode, the program

main = print mystery

is actually the same as

main :
    a = 0
    b = 10
    print "[" 
    while( True ) :
       print a , 
       print b ,
       a += 1
       b += 1

A principled approach to tackle such problems is to name all your interim entities, the inner thunks behind lazy data constructors (here, :), as they come into being, forced into WHNF by the demands of lazy evaluation. Then the mystery disappears:

mystery = 0  : 10 : map (+1) mystery
        = x1 : t1 
  where 
  x1 = 0
  t1 = 10 : map (+1) mystery
     = x2 : t2
    where
    x2 = 10
    t2 = map (+1) mystery
       = map (+1) (x1 : t1)
       = x1 + 1 : map (1+) t1         -- by definition of map
       = x3     : t3
      where
      x3 = x1 + 1 = 0 + 1 = 1
      t3 = map (1+) t1 = map (1+) (x2 : t2)
         = x2 + 1 : map (1+) t2       --    = x_{n} + 1 : ...
         = x4     : t4                --    = x_{n+2}   : ...
        where
        ....

At no point do we get any function other than (1+) in this reduction process, nor do we ever get more than one of them stacked up in a row.

All we get is xn := 1 + xn-2, repeatedly, for all n above 1.



来源:https://stackoverflow.com/questions/56512596/why-is-this-recursive-map-function-only-being-applied-to-the-last-two-elements-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!