how to do recursive discriminated unions by value? - f#

In F# is it possible to have a discriminated union based on both a type and a value?
Here's an attempt at expressing this without knowing what the syntax should look like.
type Foo =
| A of int * Foo
| B of string where B.name = "1" * Foo
| C of string where C.name = "2" * Foo
| Empty

I'm not entirely sure what you're trying to achieve. But, if you want to create a type that will have a name property when which is "1" when the type is B and "2" when it is C, then you can add a member:
type Foo =
| A of int * Foo
| B of Foo
| C of Foo
| Empty
member x.Name =
match x with
| B _ -> "1"
| C _ -> "2"
| _ -> failwith "Name is not available!"
If you were hoping to use the numbers in pattern matching, then you can define an active pattern. Say you have a type with just A or B (which has a name):
type Foo =
| A of int
| B of string * Foo
Now you can write an active pattern that lets you distinguish between A, B with name "1" and B with name "2":
let (|A|B1|B2|) x =
match x with
| A n -> A n
| B("1", foo) -> B1 foo
| B("2", foo) -> B1 foo
| _ -> failwith "Invalid B"
If you now have a value foo, you can pattern match against these three cases:
match foo with
| A n -> ...
| B1 subfoo -> ...
| B2 subfoo -> ...

Related

Generic pattern matching in function argument

Let say I have DU of three types and a function which accepts this DU as a parameter:
type A = decimal<p>
type B = decimal<p>
type C = decimal<p>
type ABC = A of A | B of B | C of C
let myfunc (val: ABC) =
match val with
| A v -> ...
| B v -> ...
| C v -> ...
Is there a better way to define a function which accepts DU of only A and B without defining new type explicity?
This is a working example:
type AB = A2 of A | B2 of B
let myfunc2 (val: AB) =
match val with
| A2 v -> ...
| B2 v -> ...
This is how I would like it to be:
let myfunc2 (val: A|B) =
match val with
| A v -> ...
| B v -> ...
The language feature you're asking for is open variants, which exists in OCaml, but not in F#. For instance,
type ABC = A of int | B of int | C of int
type AB = A of int | B of int
let myfunc (x: AB) = ...
is legal in OCaml. This can also be achieved with type-erased DUs (vote for it here!).
DU cases in F# are not actual types, but the base type (ABC) with a tag denoting which union case it is. And since there are no types which exist separately, it follows that they cannot be used as a type constraint.
You can however try and work around this with Choice. The idea is to build single case DUs and then combine them with Choice<T1, T2...>.
type A = A of int
type B = B of int
type C = C of int
type ABC = Choice<A, B, C>
type AB = Choice<A, B>
let matchAb (x: AB) =
match x with
| Choice1Of2 (A a) -> a
| Choice2Of2 (B b) -> b

Can one set default values for Discriminated Union types?

I implemented a Discriminated Union type that would be used to select a function:
type BooleanCombinator =
| All
| Some
| None
| AtLeast of int
| MoreThan of int
| NotMoreThan of int
| LessThan of int
| ExactlyOne
| ExactlyTwo
| AllButOne
| AllButTwo
let boolToInt (b: bool) : int = if b then 1 else 0
let combineBooleans (combinator : BooleanCombinator)
(bools : bool list)
: bool =
let n = List.sumBy boolToInt bools
match combinator with
| BooleanCombinator.All -> List.forall id bools
| BooleanCombinator.Some -> bools |> List.exists id
| BooleanCombinator.None -> bools |> List.exists id |> not
| BooleanCombinator.AtLeast i -> n >= i
| BooleanCombinator.MoreThan i -> n > i
| BooleanCombinator.NotMoreThan i -> n <= i
| BooleanCombinator.LessThan i -> n < i
| BooleanCombinator.ExactlyOne -> n = 1
| BooleanCombinator.ExactlyTwo -> n = 2
| BooleanCombinator.AllButOne -> n = bools.Length - 1
| BooleanCombinator.AllButTwo -> n = bools.Length - 2
This looked Ok to me but the compiler started to look at all instances of Some and None as belonging to this DU, instead of the Option DU.
I do not want to go through all of my code replacing Some with Option.Some and None with Option.None.
Is there a way to tell the compiler that unqualified Some and None are actually Option.Some and Option.None?
Or should I just give different names to these DU cases, like AtLeastOne and ExactlyZero
The general rule for resolving name collisions in F# is "last declaration wins". Because your custom DU is declared after Option, its constructors Some and None win over those of Option.
But this rule offers a way to fix the problem: you just need to "reassert" the declarations after your custom DU:
type Bogus = Some of int | None
let g = function Some _ -> 42 | None -> 5
let x = Some 42
let inline Some a = Option.Some a
let inline None<'a> = Option.None : 'a option
let (|Some|None|) = function | Option.Some a -> Some a | Option.None -> None
let f = function Some _ -> 42 | None -> 5
let y = Some 42
If you inspect the types of g, x, f, and y in the above code:
> g
g : Bogus -> int
> f
f : 'a option -> int
> x
Bogus
> y
int option
The function g and value x were inferred to have type Bogus -> int and Bogus respectively, because Some and None in their bodies refer to Bogus.Some and Bogus.None.
The function f and value y were inferred to have Option-related types, because Some and None in their bodies refer to the Some function and the (|Some|None|) active pattern that I defined just above.
Of course, this is a rather hacky way to restore status quo. This will convince the compiler, but humans will still have a hard time reading your code. I suggest you rename the cases of your DU instead.
You can mark your DU with [<RequireQualifiedAccess>] attribute.
This means that you will be required to qualify the case name with the type whenever you use it in the code - which is something you do now anyway in your match expression.
That way an unqualified Some would still be resolved to mean Option.Some, despite the fact that you reuse the name.
It's a useful technique to know when you want to use a snappy name for a DU case - like None, Yes, Failure etc. - that by itself would be ambiguous or confusing to the reader (or the compiler, for that matter).

Simplifying nested pattern matching F#

I am writing a simple expressions parser in F# and for each operator I want only to support a certain number of operands (e.g. two for Modulo, three for If). Here is what I have:
type Operator =
| Modulo
| Equals
| If
let processOperator operands operator =
match operator with
| Modulo ->
match operands with
| [ a:string; b:string ] -> (Convert.ToInt32(a) % Convert.ToInt32(b)).ToString()
| _ -> failwith "wrong number of operands"
| Equals ->
match operands with
| [ a; b ] -> (a = b).ToString()
| _ -> failwith "wrong operands"
| If ->
match operands with
| [ a; b; c ] -> (if Convert.ToBoolean(a) then b else c).ToString()
| _ -> failwith "wrong operands"
I would like to get rid of or simplify the inner list matches. What is the best way to accomplish this? Should I use multiple guards ?
open System
type Operator =
| Modulo
| Equals
| If
let processOperator operands operator =
match (operator, operands) with
| Modulo, [a: string; b] -> string ((int a) % (int b))
| Equals, [a; b] -> string (a = b)
| If, [a; b; c] -> if Convert.ToBoolean(a) then b else c
| _ -> failwith "wrong number of operands"
But I would suggest to move this logic of the operands to the parser, this way you get a clean operator expression, which is more idiomatic and straight forward to process, at the end you'll have something like this:
open System
type Operator =
| Modulo of int * int
| Equals of int * int
| If of bool * string * string
let processOperator = function
| Modulo (a, b) -> string (a % b)
| Equals (a, b) -> string (a = b)
| If (a, b, c) -> if a then b else c
Fold in the operands matching:
let processOperator operands operator =
match operator, operands with
| Modulo, [a; b] -> (Convert.ToInt32(a) % Convert.ToInt32(b)).ToString()
| Equals, [a; b] -> (a = b).ToString()
| If, [ a; b; c ] -> (if Convert.ToBoolean(a) then b else c).ToString()
| _ -> failwith "wrong number of operands"
Better yet, if you can, change the datatype to the following.
type Operator =
| Modulo of string * string
| Equals of string * string
| If of string * string * string
Then in the match, you can no longer fail.

Auto generation of predicates and accessors for discriminated unions in F#

Is it possible in F# to automatically generate predicates and accessors for an arbitrary algebraic data type in type-safe manner?
For example, if we have user defined type:
type A =
B of string
| C of int * sting
should be generated something like this:
type A =
B of string
| C of int * sting
with
member __.isB = match __ with B -> true | _ -> false
member __.isC = match __ with C -> true | _ -> false
member __._1 = match __ with B(x) -> Some(x) | _ -> None
member __._2 = match __ with C(x,_) -> Some(x) | _ -> None
member __._3 = match __ with C(_,x) -> Some(x) | _ -> None
It will be better if can specify names for accessors may be with annotation like this:
[<GenerateAccessors(["BName", "CName", "Value"])>]
May be it can not be done or I should use records instead discriminated unions (DU) if I want to siplify access to inner data. But it's more simply to use patten matching with DUs and I want both of this profits - simply pattern matching and simply "direct data access" - in the same time.
You can reflect over a discriminated union using FSharpType.GetUnionCases and generate code using the F# CodeDOM available in the F# PowerPack or simply by writing text.
open Microsoft.FSharp.Reflection
type A = B of string | C of int * string
let generate t =
let cases = FSharpType.GetUnionCases(t)
printfn "type %s with" t.Name
for case in cases do
printfn "\tmember value.is%s = " case.Name
let fields =
match [for field in case.GetFields() -> "_"] with
| [] -> ""
| fields -> " (" + (fields |> String.concat ",") + ")"
printfn "\t\tmatch value with %s%s -> true | _ -> false" case.Name fields
generate typeof<A>
Generates an F# type extension:
type A with
member value.isB =
match value with B (_) -> true | _ -> false
member value.isC =
match value with C (_,_) -> true | _ -> false

Built-in "< > compare" doesn't work with "IComparable<T>"?

I have a Discriminated Union, and I hope to use built in operators like > < compare max for it.
[<CustomComparison>]
type SymbolType =
| A
| B
| C
| D
interface IComparable<SymbolType> with
member x.CompareTo y =
match x, y with
| A, A-> 0
| A, _ -> 1
| _, A-> -1
| _, _ -> 0
I understand I can use IComparable, but then i have to do a null check, what's worse is that I have to cast it like (SymbolType) y which I assume would be time consuming.
You can already use standard comparison operators on the type. The built-in implementation uses the order of declarations of the individual cases, so:
type SymbolType = A | B | C | D
// Behavior of built-in comparison
A < B = true
D <= C = false
max B D = D
This looks very fragile, so maybe it is not the best thing to rely on. If you have cases that do not contain other values, you can use enum instead of discriminated union and define the ordering you wish:
type SymbolType =
| A = 1
| B = 2
| C = 4
| D = 3
// The order is now defined by your code
SymbolType.C < SymbolType.D = false
You can just implement the required methods with thin wrappers:
[<CustomComparison>]
[<CustomEquality>]
type SymbolType =
| A
| B
| C
| D
override x.Equals y =
match y with
| :? SymbolType as t -> (((x :> IComparable<_>).CompareTo) t)=0
| _ -> false
interface IComparable with
member x.CompareTo y =
match y with
| :? SymbolType as t -> ((x :> IComparable<_>).CompareTo) t
| _ -> failwith "bad comparison"
interface IComparable<SymbolType> with
member x.CompareTo y =
match x, y with
| A, A-> 0
| A, _ -> 1
| _, A-> -1
| _, _ -> 0
This way does avoid any duplicate typing.
On CLR, operators are static functions, so you can't define them in an interface. But boxing can also be avoided if your use the interface as a constraint of type parameter of a generic function.
int Compare<T>(T lhs, T rhs) where T : IComparable<T>
{
return lhs.CompareTo(rhs) // no boxing
}
Sorry, I'm not familiar with F#, so I wrote the example in C#.

Resources