F# match question
this is what i have so far:
type u = {str : string} //some type that has some property str (for simplicity, only one)
type du=
| A of u
| B of u // some discriminated union that carries u with it
then, somewhere i have a sequence of du that i am doing distinctBy and the property to do distinct is str. best i could come up with is this:
Seq.distinctBy (fun d -> match d with (A u|B u) -> u.str)
the code works, but i don't like having to match on a and b of the discr开发者_高级运维iminated union and would like to replace the match with something.
question is, what? :)
EDIT:
in my case, a and b of the discriminated union will always carry same type u with them, one solution is to get rid of du and add it's string form to type u and simplify this whole mess, but i would like to keep it this way for now because i was going to do matches and such on the a and b...
How about doing the match one time as a property of du?
type u = {str : string}
type du =
| A of u
| B of u with
member this.U =
match this with
(A u | B u) -> u
[A {str="hello"}; B {str="world"}; A {str="world"}]
|> Seq.distinctBy (fun x -> x.U.str)
//val it : seq<du> = seq [A {str = "hello";}; B {str = "world";}]
However, I have a couple ideas which may model the relationship between u and du better while satisfying your "EDIT" concerns. One way is simply using tuples:
type u = {str : string}
type du =
| A
| B
//focus on type u
[A, {str="hello"}; B, {str="world"}; A, {str="world"}]
|> Seq.distinctBy (fun (_,x) -> x.str)
//val it : seq<du * u> = seq [(A, {str = "hello";}); (B, {str = "world";})]
//focus on type du
let x = A, {str="hello"}
match x with
| A,_ -> "A"
| B,_ -> "B"
//val it : string = "A"
Another way is to switch it around and add du to u:
type du =
| A
| B
type u = { case : du; str : string}
//focus on type u
[{case=A; str="hello"}; {case=B; str="world"}; {case=A; str="world"}]
|> Seq.distinctBy (fun x -> x.str)
//val it : seq<u> = seq [{case = A;
// str = "hello";}; {case = B;
// str = "world";}]
//focus on type du
let x = {case=A; str="hello"}
match x with
| {case=A} -> "A"
| {case=B} -> "B"
//val it : string = "A"
You really can't simplify it as much as you describe but you can simplify it. Thanks @Tomas Petricek
[ A { str = "A" }; B { str = "B" }; B { str = "B" } ]
|> Seq.distinctBy (fun (A u | B u) -> u.str)
|> Seq.toArray;;
Output
[| A {str = "A";}; B {str = "B";} |]
I'm a bit new to F# but hopefully this will help. It seems to me that Active Patterns might make your life easier in trying to cut down what you need to type in your pattern matching. Instead of using A a | B b you can use the active pattern AorB in it's place.
type u = { str : string }
type du =
| A of u
| B of u
let (|AorB|) (v:du) =
match v with
| A a -> a
| B b -> b
[A { str = "A" }; B { str = "B"}; A { str = "A"}]
|> Seq.distinctBy (fun d ->
match d with
| AorB s -> s)
|> Seq.iter (fun i -> match i with AorB c -> printfn "%s" c.str)
With Stephen's addition the final expression can be written thusly.
[A { str = "A" }; B { str = "B"}; A { str = "A"}]
|> Seq.distinctBy (|AorB|)
|> Seq.iter (fun i -> match i with AorB c -> printfn "%s" c.str)
精彩评论