2009-05-07 4 views
31

은 무한한 목록에서이 제대로 작동하지만 하프웰 코드는 정상적으로 작동하지 않습니다.하지만 이해할 수 없습니다. 이유가이므로 성공적으로 수행 할 수 있습니다. (전 원래 코드를 수정하여 무한한 목록을 처리하지 못했지만 온라인에서 다른 코드의 내용을 통합 할 수있었습니다. 갑자기이 코드는 작동하지만 왜 그런지는 알 수 없습니다). foldr의왜이 Haskell 코드가 무한리스트와 함께 성공적으로 작동합니까?

myAny :: (a -> Bool) -> [a] -> Bool 
myAny p list = foldr step False list 
    where 
     step item acc = p item || acc 

나의 이해는이 목록에있는 모든 항목을 통해 루프 (그리고 아마도 그 이해가 불완전) 것입니다. 그렇다면 "단계"기능이 어떻게 표현되는지는 중요하지 않습니다 ... 코드가 무한 루프를 처리 할 수 ​​없어야합니다. 그러나

다음 작품 :

*Main Data.List> myAny even [1..] 
True 

나를 이해하는 데 도움이 바랍니다 : 왜?

답변

46

http://en.wikipedia.org/wiki/Lazy_evaluation가의 하스켈이 표현식을 평가하는 방법의 우리의 머리에 약간의 추적을하자 참조하십시오. 대입 각 줄에 등호를 위해 동일, 표정은 꽤 빨리 True로 평가 :

myAny even [1..] 
foldr step False [1..] 
step 1 (foldr step False [2..]) 
even 1 || (foldr step False [2..]) 
False || (foldr step False [2..]) 
foldr step False [2..] 
step 2 (foldr step False [3..]) 
even 2 || (foldr step False [3..]) 
True || (foldr step false [3..]) 
True 

acc이 평가되지 않은 썽크 (게으른 평가)로 전달되기 때문에이 작품뿐만 아니라 || 기능이 첫 엄격하기 때문에 인수

True || and (repeat True) 

을하지만이되지 않습니다 :

그래서이 종료의 정의에서

and (repeat True) || True 

봐 || foldr의

True || _ = True 
False || x = x 
+4

또한 코드가 두 개 이상의 요소를 계산하지 않는다는 것을 확인할 수 있습니다 :'myAny p list = foldr (\ iia -> trace (show i) (pi || a))''- True' – viraptor

+0

와우, 이것은 매우 눈을 뜨게하는 반응이었습니다. 우선, 나는 나 앞에서 foldr의 정의로 시작하지 않았다. 나는 그 코드가 아직 모르는 고급 기능을 사용할 것이라고 생각했기 때문에 최후의 수단으로 만 보았습니다. 귀하의 답변을 통해 제가 한 번 더 살펴보고 많은 것을 명확히했습니다. foldr 자체는 "평범한 구식"구조 재귀를 사용하고 있습니다. 네가 그걸 깨뜨린 것을 사랑해. 감사. –

+0

BTW는 || 최초의 arg에서 완전하게 엄격한가, 또는 단지 최초의 인수를 「우선한다」것인가. 예를 들어, arg 2가 이미 eval 된 적이 있었지만 arg 1이 여전히 단순한 썽크 였다면 어떨까요? arg 2가 거짓이라고 말하십시오. 하스켈은 반대 방향으로 단락 되었습니까? 감사. –

1

여기서 핵심은 하스켈이 엄격하지 않은 언어라는 것입니다. "비 엄격"은 엄격하지 않은 함수를 허용한다는 의미이며, 이는 함수 매개 변수가 사용되기 전에 완전히 평가되지 않을 수도 있음을 의미합니다. 이것은 분명히 "결과가 요구 될 때까지 계산을 지연시키는 기술"이라는 게으른 평가를 허용합니다.

시작 this Wiki article

+0

좋아, 나는 게으른 평가에 대해 알았어. 하지만 그 점을 연결하는 데 도움이 필요합니다 위의 코드가 작동합니다. 한편, 나는 위키 문서를 살펴볼 것이다. 감사. –

1

에서 나는 하스켈 모르겠지만, 나는 귀하의 경우, 그것은 때문에 게으른 평가의 작동하는지 생각한다. 무한히 길게 목록을 처리 할 수 ​​있으므로 액세스 할 때 필요에 따라 결과를 계산합니다.

+0

좋은 기사입니다. 링크를 이용해 주셔서 감사합니다. –

18

나의 이해가 그것을 목록의 모든 항목을 통해 의지 루프 (그리고 아마도 그 이해 이 불완전)입니다 :이 경우 이유를 볼 수 있습니다.

foldr (foldl과 달리) 목록의 모든 항목을 반복 할 필요가 없습니다. foldr이 정의 된 방법을 살펴 보는 것이 좋습니다.

foldr 호출이 평가
foldr f z []  = z 
foldr f z (x:xs) = f x (foldr f z xs) 

, 그것은 f 함수에 대한 호출의 평가를 강제. 그러나 foldr에 대한 재귀 호출이 함수 f에 대한 인수에 어떻게 포함되는지 유의하십시오. 이 재귀 호출은 f이 두 번째 인수를 평가하지 않으면 평가되지 않습니다.

+0

좋은 지적. 처음에는 foldr 정의가 하스켈 지식의 수준에서 이해할 수 있을지 알지 못했습니다. 재귀 호출이 의도적으로 함수 인수에 삽입되어 썽크가되게하는 방법을 지적합니다. 하스켈의 개발팀이 많이하는 일이 뭔가요? 함수가 필요하지 않은 경우도 있지만 인수를 전달하여 썽크가된다는 것을 알기 때문에 함수를 만들면됩니까? –

+2

Charlie, 우리가 사용하고있는 Haskell이기 때문에 무언가가 강요되지 않으면 평가되지 않습니다. –