Я пытаюсь написать свой собственный построитель Либо как часть моего стремления изучить вычислительные выражения в f #, но я столкнулся с тем, что, как мне кажется, является проблемой с методом Combine. Мой код до сих пор:
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()
С помощью этого кода я тестирую Combine двумя тестами:
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))
Первый тест проходит, как я и ожидал, но второй тест завершается со следующим сообщением:
Возникло исключение: «NUnit.Framework.AssertionException» в nunit.framework.dll либо проверяет/возвращает успех с вложенными рабочими процессами: Ошибка: Ожидается:
<Success 5>
Но было:<Failure>
Я не понимаю. x
не выдается, так почему же это влияет на мой родительский рабочий процесс? Если я двигаться пусть! ниже выход тест проходит. Я смотрю на свою реализацию Combine, и мне кажется, что для пары Failure*Success
фактический порядок аргументов не повлияет на результат, но все же кажется, что это так.