2017-11-13 16 views
3

f #의 계산 표현식을 배우기 위해 제 자신의 Either 빌더를 쓰려고하는데, Combine 메소드로 문제가 있다고 생각하는 벽에 부딪혔습니다. 지금까지 내 코드 : 내가 기대하는 것처럼,중첩 된 워크 플로우에서 yield가 발생했습니다.

let either = new EitherBuilder() 
... 
testCase "returns success from 3 yields" <| 
    fun _ -> 
     let value = either { 
      yield! Failure 
      yield 4 
      yield! Failure 
      } 
     value |> should equal (Success(4)) 
testCase "returns success with nested workflows" <| 
    fun _ -> 
     let value = either { 
      let! x = either { 
       yield! Failure 
       } 
      yield 5 
      } 
     value |> should equal (Success(5)) 

첫 번째 테스트를 통과,하지만 두 번째 테스트는 다음과 같은 메시지와 함께 실패합니다 : 나는 두 가지 테스트를 결합 테스트 코드와

type Result<'a> = 
    | Failure 
    | Success of 'a 

type EitherBuilder() = 
    member this.Bind(m,f) = 
     match m with 
     | Failure -> Failure 
     | Success(x) -> f x 
    member this.Yield x = 
     Success(x) 
    member this.YieldFrom x = 
     x 
    member this.Combine(a,b) = 
     match a with 
     | Success(_) -> a 
     | Failure -> b() 
    member this.Delay y = 
     fun() -> y() 
    member this.Run(func) = 
     func() 

던져

예외 : 'NUnit.Framework.AssertionException를' nunit.framework.dll 중 시험에서이/중첩 된 워크 플로우 성공을 반환 실패 : 예상 : <Success 5>하지만 : <Failure>

나는 그것을 얻지 못한다. x이 생성되지 않으므로 부모 워크 플로에 어떤 영향을 줍니까? 나는 움직여! 아래의 테스트 합격. 내 결합 구현을 응시하고있어이 Failure*Success 쌍의 결과에 영향을주지 것 인수의 실제 순서 나를 그 찾지 만 아직 표현에서

답변

4

do!let! 조항이 Bind에 desugared 취득하는 것처럼 보인다 전화. 즉, let! x = ...을 실행하면 Bind이 호출됩니다.

은보다 구체적으로, 두 번째 예는 다음에 desugared됩니다 :

let value = 
    either.Bind(
     either.YieldFrom Failure, // yield! Failure 
     fun x ->     // let! x = 
      either.Yield 5   // yield 5 
    ) 

그래서 심지어 yield 5에 도달하지 - 계산은 let! x =에서 멈 춥니 다. 에 내부 계산을 위해서는

let (뱅없이)를 사용하여, 외부 하나의 "부분이 없다"

let value = either { 
    let x = either { 
     yield! Failure 
     } 
    yield 5 
    } 

이 올바르게 Success 5를 반환합니다.

+0

나는이 결과를 놓쳐 버렸다!, thanks :) – DevNewb