2014-10-19 4 views
6

는 접이식 종료가 아닌 우리가 달리의 돌발 생각해 보자 :번역 제도 호출 하스켈 callCC/참조

(call/cc (lambda (folded) 
    (stream-fold 
    (lambda (acc v) 
     (if (< v 5) 
     (cons v acc) 
     (folded acc))) 
    '() 
    (in-naturals 0)))) 
; returns '(4 3 2 1 0) 

위의 코드의 하스켈 해당하는이 코드가하는

callCC $ \folded -> foldl (\acc v -> if v < 5 then v:acc else folded acc) [] [0..] 

것 컴파일되지 않고 접힌 식에 무한한 타입을 만들 수 없다는 것에 대해 불평한다. 나는 이미 Y 결합 자와 같은 경우 이런 종류의 오류를 제거하는 방법에 대한 아이디어를 갖고 있지만, 같은 접근법이 여기서는 효과가없는 것으로 보인다. 이런 상황에 올바른 접근 방법은 무엇입니까?

+6

'foldl' 대신'foldM'을 사용하십시오. 여기서'v : acc'와'folded acc'는 같은 타입을 반환하지 않습니다. –

답변

6

예; j로. 아브라함 손은 말합니다,

import Control.Monad.Trans.Cont 
import Control.Monad 

bar :: Cont r [Int] 
bar = callCC $ \folded -> 
    foldM (\acc v -> do 
     when (v >= 5) $ folded acc 
     return $ v : acc) [] [0..] 

thing = runCont bar id 

작품. 페이지에 설명으로 모든

+1

답변 해 주셔서 감사합니다. 이 경우 작동하지만 다소 전문화 된 것처럼 보입니다. call/cc를 사용하여 Scheme 코드를 하스켈 (Haskell)로 번역하는 일반적인 접근법이 있습니까? 아니면 항상 형식 시그니처를보고 각 사례를 개별적으로 고려해야합니까? – zabolekar

1

첫째, 계획 통화/CC와 하스켈 callCC는 다소 다른 것들 undelimited continuations are not functions

가장 큰 문제는 모든 전화/CC를 필요로하지 않을 수있다 - 심지어에 계획. 루프를 깨뜨린 사례는 예외를 사용하여 구현하는 것이 훨씬 더 효율적입니다. 효율성 측면에서 볼 때 더 좋습니다 (어쨌든 사용하지 않을 연속성을 캡처 할 필요가 없음). 작업이 현재 연속을 중단하는 것이라면 그 목적을위한 도구가 있습니다. R7RS는이를 인정하고 예외를 도입했습니다. Haskell에서 예외를 사용하려면 Error 또는 Either 모나드를 사용하십시오. 예를 들어 코드에

baz :: Either [Int] [Int] 
baz = foldM (\acc v -> do 
     when (v >= 5) $ Left acc 
     return $ v : acc) [] [0..] 

thing1 = either id id baz 

제어 연산자에 대한 경험이 거의없는 경우 연산자 호출/cc가 Scheme에 도입되었습니다. 이제 우리는 많은 경험을 가지고 있으며, call/cc의 많은 심각한 단점들이 밝혀졌습니다. 자세한 내용에 관심이있는 경우 다음 페이지에서 call/cc 문제에 대한 자세한 내용을 설명합니다. An argument against call/cc