私はF#に新たなんだ、これは愚かな質問である場合や構文はビットオフにすることもあればそう予めご容赦します。うまくいけば、それはとにかく、質問の主旨を理解することが可能です。
私は何を達成したいことはコンなどの可能性があるResult
の(またはEither
異なるエラータイプ(判別共用体)を有するか、似たような)せずに作成する明示的な二つの他の判別組合の組合を含んで判別組合を。
私は例を提示してみましょう。
のは、私はタイプがあるとしましょうPerson
。このように定義します:
type Person =
{ Name: string
Email: string }
あなたが名前を検証する機能を持っていることを想像して:
type NameValidationError =
| NameTooLong
| NameTooShort
let validateName person : Result<Person, NameValidationError>
そして、メールアドレスを検証している別:
type EmailValidationError =
| EmailTooLong
| EmailTooShort
let validateEmail person : Result<Person, EmailValidationError>
今、私が作曲したいvalidateName
とvalidateEmail
、しかし、問題は、エラーの種類をしていることであるResult
さまざまな種類があります。私は何を達成したいことは、私はこのような何かを行うことができる機能(またはオペレータ)です。
let validatedPerson = person |> validateName |>>> validateEmail
(|>>>
「魔法演算子」です)
使用して|>>>
のエラータイプをvalidatedPerson
の労働組合なりNameValidationError
とEmailValidationError
:
Result<Person, NameValidationError | EmailValidationError>
ちょうどそれを明確にし、それが構成チェーン、IEの機能を使用する任意の数に可能なはずです。
let validatedPerson : Result<Person, NameValidationError | EmailValidationError | XValidationError | YValidationError> =
person |> validateName |>>> validateEmail |>>> validateX |>>> validateY
以下のような言語ではReasonMLあなたはと呼ばれるものを使用することができます多型変異体をしかし、これはF#では使用できません afaictとして。
それは、労働組合の種類(または任意の他の技術)とジェネリックを使用して何とか模倣多型変異することは可能であろう!それともこれは不可能でしょうか?
いくつかの興味深いあります消去型労働組合のための提案は活字スタイル匿名組合の制約を考慮し、。
type Goose = Goose of int
type Cardinal = Cardinal of int
type Mallard = Mallard of int
// a type abbreviation for an erased anonymous union
type Bird = (Goose | Cardinal | Mallard)
あなた与える魔法のオペレータNameValidationError | EmailValidationError
のタイプを持っているでしょうが、コンパイル時にのみ存在します。それはに消去されますobject
実行時。
しかし、それはので、多分我々はまだ消去自分自身を行うことによって、いくつかの読み取り可能なコードを持つことができ、アンビルにはまだですか?
組成演算子は「消去」(本当に箱、)結果のエラータイプでした:
let (|>>) input validate =
match input with
| Ok(v) -> validate v |> Result.mapError(box)
| Error(e) -> Error(box e)
私たちは、型マッチングDUケースが口に合うようにする部分アクティブパターンを持つことができます。
let (|ValidationError|_|) kind = function
| Error(err) when Object.Equals(kind, err) -> Some ()
| _ -> None
(スーパーバイアスの検証を含む)例:
let person = { Name = "Bob"; Email = "[email protected] "}
let validateName person = Result.Ok(person)
let validateEmail person = Result.Ok(person)
let validateVibe person = Result.Error(NameTooShort)
let result = person |> validateName |>> validateVibe |>> validateEmail
match result with
| ValidationError NameTooShort -> printfn "Why is your name too short"
| ValidationError EmailTooLong -> printfn "That was a long address"
| _ -> ()
これは、上のシャントます validateVibe