EitherWriter를 만드는 방법을 보여 드리겠습니다. Either
과 Writer
을 주문하는 방법에 따라 다음 중 하나를 만들 수있는 방법은 두 가지가 있지만 그 예를 보여 드리겠습니다. 원하는 워크 플로우와 가장 비슷합니다.
라이터를 단순화하여 string list
에만 기록하도록하겠습니다. 더 완전한 작성자 구현은 mempty
및 mappend
을 사용하여 적절한 유형을 추상화합니다.
유형 정의 :
type EitherWriter<'a,'b> = EWriter of string list * Choice<'a,'b>
기본 기능 :
나는 독립 모듈에 다음을 정의하고 내가 직접 사용하거나 계산 식을 만들 수를 참조 할 수 있습니다 좋아
let runEitherWriter = function
|EWriter (st, v) -> st, v
let return' x = EWriter ([], Choice1Of2 x)
let bind x f =
let (st, v) = runEitherWriter x
match v with
|Choice1Of2 a ->
match runEitherWriter (f a) with
|st', Choice1Of2 a -> EWriter(st @ st', Choice1Of2 a)
|st', Choice2Of2 b -> EWriter(st @ st', Choice2Of2 b)
|Choice2Of2 b -> EWriter(st, Choice2Of2 b)
.
type EitherWriterBuilder() =
member this.Return x = return' x
member this.ReturnFrom x = x
member this.Bind(x,f) = bind x f
member this.Zero() = return'()
let eitherWriter = EitherWriterBuilder()
이 중 실제인가 : 다시 말하지만, 나는 간단하게 그냥 가장 기본적인 사용 가능한 구현을 할거야?
F 재미와 이익을위한 F는 railway oriented programming에 대한 훌륭한 정보와 경쟁 방식에 비해 장점이 있습니다.
이러한 예제는 사용자 지정 Result<'TSuccess,'TFailure>
을 기반으로하지만 물론 F #의 기본 제공 Choice<'a,'b>
형식을 사용하여 동일하게 적용 할 수 있습니다.
우리는이 철도 방향 형식으로 표현 된 코드를 만날 가능성이 있지만 EitherWriter
으로 직접 사용할 수 있도록 미리 작성된 코드는 거의 없습니다. 따라서이 방법의 실용성은 단순 성공/실패 코드에서 위에 제시된 모나드와 호환 가능한 것으로 쉽게 변환되는 것에 달려 있습니다. 여기
성공의 예/기능 장애 :
는
let divide5By = function
|0.0 -> Choice2Of2 "Divide by zero"
|x -> Choice1Of2 (5.0/x)
이 함수는 제공된 번호 5로 분할한다. 이 숫자가 0이 아니면 결과를 포함하는 성공을 반환하고 제공된 숫자가 0이면 0으로 나누려고했음을 알리는 실패를 반환합니다.
이제는 이와 같은 기능을 EitherWriter
에서 사용할 수있는 것으로 변환하는 도우미 함수가 필요합니다. 그렇게 할 수있는 함수는 이것이다 :
그것은, 실패를 기록하는 방법을 설명하는 기능을 성공을 로그인하는 방법을 설명하는 기능과
Either
모나드에 대한 바인딩 기능을 소요하고는
EitherWriter
에 대한 바인딩 기능을 반환
let eitherConv logSuccessF logFailF f =
fun v ->
match f v with
|Choice1Of2 a -> EWriter(["Success: " + logSuccessF a], Choice1Of2 a)
|Choice2Of2 b -> EWriter(["ERROR: " + logFailF b], Choice2Of2 b)
모나드.
우리는이처럼 사용할 수 있습니다
let ew = eitherWriter {
let! x = eitherConv (sprintf "%f") (sprintf "%s") divide5By 6.0
let! y = eitherConv (sprintf "%f") (sprintf "%s") divide5By 3.0
let! z = eitherConv (sprintf "%f") (sprintf "%s") divide5By 0.0
return (x, y, z)
}
let (log, _) = runEitherWriter ew
printfn "%A" log
을 그런 다음 반환
["Success: 0.833333"; "Success: 1.666667"; "ERROR: Divide by zero"]
IIRC, http://fsprojects.github.io/FSharpx.Extras가 있습니다. 또한 여기에 예제를 제공합니다 : http://blog.ploeh.dk/2016/04/11/async-as-surrogate-io –
다음은 [리더, 작성자 및 상태 모나드를 결합한 예제]입니다 (http : // tomasp .net/blog/2014/update-monads /)에서 F #을 사용합니다. 당신이 설명하는 것을 수행하는 대안 * 방법은 F #에서이 [대수 효과 및 핸들러 사용 예제] (http://www.fssnip.net/jl)를 통해 이루어질 수 있습니다. –
정확히 찾고있는 것이 없지만이 작은 프로젝트는 결합 된 리더/상태 모나드를 사용합니다 : https://github.com/TheInnerLight/RemoteMonad/ (Haskell) 코드의 일부 F # 번역입니다. 이 글 : http://www.cs.rhul.ac.uk/home/ucac009/publications/remote-monad.pdf 또한, (F #의 모나드 입출력을 위해) 개발중인 IO 라이브러리는 더 복잡한 숫자를 구현합니다 모나드 루프와 같은 모나드 연산은 꽤 잘 문서화되어 있습니다 : https : // github.com/TheInnerLight/NovelIO – TheInnerLight