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 이란 거지
참 쉽죠?
무슨 타입에러 컴파일 타임에 못보는 인터프리터마냥 런타임에 어느순간 평가되면서 무한루프 터지는거 보고 알아야 하는거냐
그건 러스트도 마찬가지잖아
애초에 그거 정지 문제라 안되는게 당연한거임 ㅋㅋㅋㅋㅋ
생각해보니 그렇네
하스켈 껍데기에 현혹됐군
너 그거 하혐이야!
느긋한 평가 만세! - dc App
저번에 knapsack 문제 풀 때 우연히 후자 먼저 시도하고 전자로 고치다가 안되는 이유를 깨달았는데, 전자 먼저 시도했으면 절대 못 깨달았을듯 ㅋㅋㅋㅋ
아무래도 님 천재임 ㅇㅅㅇ - dc App
근데 whnf가 뭐임
weak head normal-form - dc App
더 어려운 단어가 나와부럿노
constructor만 구하고 내부 값은 평가 안한 상태. 예를 들어서 [1,2]의 whnf는 _:_ 임.
대충 C# Lazy<T> 객체같은건가
constructor, built-in function applied to too few arguments, lambda-abstraction - dc App
아 나도 정확히 아는건 아니라. 기괴공학도 말이 정확함
https://wiki.haskell.org/Weak_head_normal_form
이게 언어 스펙이면 하스켈 절망편이야… 그래도 iterate 구현보고 간신히 이해했다 ㄱㅅ