f# - How to map a sequence of discriminated unions (where all items are of the same case) onto a sequence of items of the type of the case? -
i have following:
type union1 = | case1 of string | case2 of int let union1s = seq { in 1..5 yield case2 }
how change union1s
sequence of type seq<int>
?
something like:
let matchcase item = match item | case1 x -> x | case2 x -> x let case2s = seq.map matchcase union1s
this attempt not work because matchcase can not return 2 different types.
the suggested answers have same problem (if understand correctly)
let matchcaseopt = function | case1 x -> x | case2 x -> x | _ -> none let case2s = seq.choose matchcaseopts unions1s
the expression x expects expects type option string in match case2
i have solved particular use-case using du of sequences.
type union1s = | case1s of seq<string> | case2s of seq<int>
you try following reflection-based, general purpose implementation:
open microsoft.fsharp.quotations open microsoft.fsharp.quotations.patterns open microsoft.fsharp.reflection let filterunioncases (branch : expr<'t -> 'union>) (inputs : 'union list) = let rec getunioncase (e : expr) = match e | newunioncase(unioncaseinfo,_) -> unioncaseinfo | lambda(_, body) -> getunioncase body | let(_, tupleget _, body) -> getunioncase body | _ -> invalidarg "branch" "not union case constructor" let getbranchcontents (uci : unioncaseinfo) (u : 'union) = let uci', fields = fsharpvalue.getunionfields(u, typeof<'union>) if uci = uci' match fields | [| field |] -> field :?> 't | _ -> fsharpvalue.maketuple(fields, typeof<'t>) :?> 't |> else none let uci = getunioncase branch inputs |> list.choose (getbranchcontents uci) filterunioncases <@ case1 @> [ case1 "string1" ; case2 2 ; case1 "string2" ] // [ "string1" ; "string2" ] filterunioncases <@ case2 @> [ case1 "string1" ; case2 2 ; case1 "string2" ] // [ 2 ]
this should work in union cases contain multiple fields.
Comments
Post a Comment