2017-09-27 3 views
1

일부 코드를 지속적으로 전달하지 않으려면 Reader 인스턴스 (->) r을 사용하여 일부 코드를 정리하기로 결정했습니다. 이제IO 내부에서 Reader`(-> r)`을 사용하여 예기치 않은 동작이 발생합니까?

let p x y = print (x,y) 
    f = ($ (1 :: Int)) 
f $ ((>>) :: forall m a. m ~ (Int -> a) => m -> m -> m) 
    (p <$> (+ 2) <*> (+ 5) :: Int -> IO()) 
    (p <$> (* 6) <*> (* 2)) 

((>>) :: forall m. m ~ IO() => m -> m -> m) 
    (f (p <$> (+ 2) <*> (+ 5) :: Int -> IO())) 
    (f (p <$> (* 6) <*> (* 2))) 

내가 의심이 문제가 그 동안이다 : 수동으로 어떤 종류의 주석이 desugaring 퍼팅 후

let p x y = print (x,y) 
    f = ($ (1 :: Int)) 

f $ do 
    p <$> (+ 2) <*> (+ 5) 
    p <$> (* 6) <*> (* 2) 
-- prints (6,2) but not (3,6) 

do 
    f $ p <$> (+ 2) <*> (+ 5) 
    f $ p <$> (* 6) <*> (* 2) 
-- prints both (6,2) and (3,6) 

:

조금 주위를 연주 후, 나는 행동에서 다음과 같은 차이를 발견 IO 인스턴스에 대해 >>이 내가 원하는 것을 수행하면, (-> r)에 대한 >>은 왼쪽면을 들여다 보는데 너무 게으른 것입니다.

내 질문은,이 게으름 문제를 실행하지 않고 이런 일을 할 수있는 방법이 있습니까 (아마도 변종입니까?).

확실하지 않은 경우 ReaderT이 경우 도움이되지만 코드를 더 복잡하게 만드는 결과를 초래할 수 있으므로이를 시도하지 않았을 것입니다.

+1

이것은 게으름과는 아무런 관련이 없습니다. – melpomene

답변

3

LHS에 엄격한 것은 전혀 중요하지 않습니다. 단지 IO 작업을 보면 단순히 수행하지 않습니다. 다른 IO 작업 (>> 등을 통해)과 결합되어야하며 결국 main (또는 GHCI에 주어진 작업)의 일부로 끝나야합니다.

즉, 이미 알고있는 것처럼 첫 번째 경우에는 (Int -> IO()) 값이 두 개 있습니다. 두 값은 두 번째 IO 작업 만 반환하는 Reader 모나드의 (>>)을 사용하여 결합됩니다. 두 번째 경우에는 두 개의 IO() 액션이 있으며 IO 모나드에서 (>>)을 사용하여 결합합니다. 물론이 두 가지를 하나의 작업으로 결합합니다.

이것은 단순히 IO 작업이 결합되는 방식, 즉 명시 적으로 결합해야하는 결과입니다. 즉, 단순히 계산하여 멀리 버리는 것만으로는 충분하지 않습니다. 당신은 무엇을 요구하는 것은 당신이 리더 모나드에서 계산이 개 번호를 물어와 유사하다 암시 함께 추가 할 :

f :: Int -> Int -> Int 
f x = (* x) 

foo :: Int -> Int 
foo = do 
    f 3 
    f 5 

bar :: Int 
bar = foo 4 

첫째는 물론 12 인 * 3 4를 계산 한 다음 그것을 멀리 던져 그리고 4 * 5, 물론 20이고, 따라서 값 막대는 20입니다. 당신이 명시 적으로 아무 것도하지 않기로 결정했기 때문에 12가 버려졌습니다 : 그것들을 더하고 bar = 32 , 또는 곱한 다음 bar = 240 또는 그런 것으로 보자. 마찬가지로 독자 계산의 내부에있는 IO() 값을 암시 적으로 결합하는 것은 올바르지 않습니다.

+0

감사합니다.'ReaderT _ IO'는 기본 동작 인 >> >>를 사용하여 원하는 작업을 끝내고 IO 동작을 구성합니다. – Javran

관련 문제