spine :: [a] -> [a]
spine = map head . iterate tail

f 0 _ = 0
f m n = m + n

xs1 = zipWith f [4..0] (tail xs1)
xs2 = zipWith f [4..0] (tail $ spine xs2)

xs1 !! 0 평가하면 무한루프고, xs2 !! 0 은 10임

일단 xs1 !! 0 을 평가 시키면 xs1을 구하려고 zipWith에서 [4..0]하고 tail xs1에 패턴 매칭을 함. 근데 tail xs1에 패턴매칭을 하려면 xs1의 whnf를 알아야 하는데, 이걸 아직 몰라서 무한루프가 됨.

근데 xs2 !! 0은 중간에 spine 이란 함수가 껴있어서, xs2가 뭔지에 상관 없이 무조건 whnf를 구할 수 있음
왜냐면

spine xs = xs !! 0 : xs !! 1 : xs !! 2 : ...
대충 이런 느낌이라 spine xs에서 xs는 내부의 컨텐츠에만 관련있고, spine(여기서는 함수이름 아님) 에는 연관이 없거든
그래서 xs2 !! 0 을 평가시키면
xs2 !! 0 = f 4 (xs2 !! 1)
xs2 !! 1 = f 3 (xs2 !! 2)
xs2 !! 2 = f 2 (xs2 !! 3)
xs2 !! 3 = f 1 (xs2 !! 4)
xs2 !! 4 = f 0 (xs2 !! 5)
순서로 평가에 들어감 (실제로는 !! 가 아니라 head랑 tail임)

근데 마지막에 f 0 (xs !! 5)에서 f가 두번째 인자에 대해 lazy 하기 때문에 이게 그냥 0으로 평가되고, 결과적으로

xs2 = 10 : 6 : 3 : 1 : 0 : []
가 됨
그래서 xs2 !! 0 = 10 이란 거지

참 쉽죠?