How can I use reflection to determine if an F# union type is an enum-like union (no fields in each case) - reflection

Terminology
For the following post, I will use the term "reference enum" to refer to an F# type that is a discriminated union with no fields in each case. For example:
type AReferenceEnum = Yes | No | Maybe
Requirements
I need a function that given a Type, returns a bool that tells whether the type is a reference enum or not.
Given these types:
type AReferenceEnum = Yes | No | Maybe
type ARecord = { name : string }
type AUnion = This of int | That of (int * string)
type AEnum = Left = 1 | Right = 2
The function would return these values
isReferenceEnum typeof<AReferenceEnum> -> true
isReferenceEnum typeof<ARecord> -> false
isReferenceEnum typeof<AUnion> -> false
isReferenceEnum typeof<AEnum> -> false
What I've tried
It seems like the implementation could be done using FSharpType and FSharpValue in the FSharp.Reflection namespace.
I know you can check FSharpType.IsUnion t to check if a type is a union, which includes reference enums.
I know you can check FSharpType.GetUnionCases t to get a UnionCaseInfo[] describing the different cases of the union type.
I know you can check FSharpValue.GetUnionFields (value, type) to get the fields of the case that value is an instance of, but not other cases.
If I could iterate the fields of each case of the union, then I could check that all cases have 0 fields, and then the type would be a reference enum.
Any suggestions?

This passes your test cases:
let isReferenceEnum ty =
if FSharpType.IsUnion ty then
FSharpType.GetUnionCases ty
|> Array.forall (fun i -> i.GetFields().Length = 0)
else
false

Related

why do I need parenthesis in this dictionary initializer, in F#

with these types:
type A =
| AA
| AB
type B =
Dictionary<int, int>()
I initialize a dictionary:
Dictionary<A, B>(dict [ (A.AA, B()); (A.AB, B()) ])
but I do not understand why I need to put parenthesis after B, in the initialization code.
the following:
Dictionary<A, B>(dict [ (A.AA, B); (A.AB, B) ])
will not compile. I understand that 'B' may represent the type and 'B()' an instance of it, but I don't understand why the '()' would represent an instance?
As an additional question:
type B =
Dictionary<int, int>()
and
type B =
Dictionary<int, int>
both seem to work. Is any of the two preferred, and, if so, why?
First of all, the declaration type B = Dictionary<int, int>() does not work for me. I get an error "Unexpected symbol '(' in member definition", exactly as I would expect. Are you sure it's working for you? Which version of F# are you using?
The type Dictionary<_,_> is a class. Classes are not the same as discriminated unions (which the type A is). They are a different sort of type.
In particular, to create a value of a class type, one needs to call a constructor and pass it some parameters. This is exactly what you're doing in your very own code:
Dictionary<A, B> (dict [ (A.AA, B()); (A.AB, B()) ])
^--------------^ ^---------------------------------^
| |
constructor |
|
parameter passed to the constructor
Some classes have multiple constructors. Dictionary is one of such types.
Some constructors have no parameters, but you still have to call them. This is what you do with empty parens.
F# models parameterless .NET methods and constructors as functions that have a single parameter, and that parameter is of type unit. This is what you're doing when you say B()
B ()
^ ^^
| |
| single parameter of type unit
|
constructor
If you just say B without a parameter, then what you get is a function of type unit -> B - that is a function that expects a single parameter of type unit and when you pass it such parameter, it would return you a value of type B.

Simulate polymorphic variants in F#?

I'm new to F# so forgive me in advance if this is a stupid question or if the syntax may be a bit off. Hopefully it's possible to understand the gist of the question anyways.
What I'd like to achieve is the possibility to compose e.g. Result's (or an Either or something similar) having different error types (discriminated unions) without creating an explicit discriminated union that includes the union of the two other discriminated unions.
Let me present an example.
Let's say I have a type Person defined like this:
type Person =
{ Name: string
Email: string }
Imagine that you have a function that validates the name:
type NameValidationError =
| NameTooLong
| NameTooShort
let validateName person : Result<Person, NameValidationError>
and another that validates an email address:
type EmailValidationError =
| EmailTooLong
| EmailTooShort
let validateEmail person : Result<Person, EmailValidationError>
Now I want to compose validateName and validateEmail, but the problem is that the error type in the Result has different types. What I'd like to achieve is a function (or operator) that allows me to do something like this:
let validatedPerson = person |> validateName |>>> validateEmail
(|>>> is the "magic operator")
By using |>>> the error type of validatedPerson would be a union of NameValidationError and EmailValidationError:
Result<Person, NameValidationError | EmailValidationError>
Just to make it clear, it should be possible to an use arbitrary number of functions in the composition chain, i.e.:
let validatedPerson : Result<Person, NameValidationError | EmailValidationError | XValidationError | YValidationError> =
person |> validateName |>>> validateEmail |>>> validateX |>>> validateY
In languages like ReasonML you can use something called polymorphic variants but this is not available in F# as afaict.
Would it be possible to somehow mimic polymorphic variants using generics with union types (or any other technique)?! Or is this impossible?
There's some interesting proposals for erased type unions, allowing for Typescript-style anonymous union constraints.
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)
The magic operator which would give you a NameValidationError | EmailValidationError would have its type exist only at compile-time. It would be erased to object at runtime.
But it's still on the anvil, so maybe we can still have some readable code by doing the erasing ourselves?
The composition operator could 'erase' (box, really) the result error type:
let (|>>) input validate =
match input with
| Ok(v) -> validate v |> Result.mapError(box)
| Error(e) -> Error(box e)
and we can have a partial active pattern to make type-matching DU cases palatable.
let (|ValidationError|_|) kind = function
| Error(err) when Object.Equals(kind, err) -> Some ()
| _ -> None
Example (with super biased validations):
let person = { Name = "Bob"; Email = "bob#email.com "}
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"
| _ -> ()
This will shunt on validateVibe
This is probably more verbose than you would like but it does allow you to put things into a DU without explicitly defining it.
F# has Choice types which are defined like this:
type Choice<'T1,'T2> =
| Choice1Of2 of 'T1
| Choice2Of2 of 'T2
type Choice<'T1,'T2,'T3> =
| Choice1Of3 of 'T1
| Choice2Of3 of 'T2
| Choice3Of3 of 'T3
// Going up to ChoiceXOf7
With your existing functions you would use them like this:
// This function returns Result<Person,Choice<NameValidationError,EmailValidationError>>
let validatePerson person =
validateName person
|> Result.mapError Choice1Of2
|> Result.bind (validateEmail >> Result.mapError Choice2Of2)
This is how you would consume the result:
let displayValidationError person =
match person with
| Ok p -> None
| Error (Choice1Of2 NameTooLong) -> Some "Name too long"
| Error (Choice2Of2 EmailTooLong) -> Some "Email too long"
// etc.
If you want to add a third validation into validatePerson you'll need to switch to Choice<_,_,_> DU cases, e.g. Choice1Of3 and so on.

Balanced tree for functional symbol table

I'm doing exercises of "Modern Compiler Implementation in ML" (Andrew Appel). One of which (ex 1.1 d) is to recommend a balanced-tree data structure for functional symbol table. Appeal mentioned such data structure should rebalance on insertion but not on lookup. Being totally new to functional programming, I found this confusing. What is key insight on this requirement?
A tree that’s rebalanced on every insertion and deletion doesn’t need to rebalance on lookup, because lookup doesn’t modify the structure. If it was balanced before a lookup, it will stay balanced during and after.
In functional languages, insertion and rebalancing can be more expensive than in a procedural one. Because you can’t alter any node in place, you replace a node by creating a new node, then replacing its parent with a new node whose children are the new daughter and the unaltered older daughter, and then replace the grandparent node with one whose children are the new parent and her older sister, and so on up. You finish when you create a new root node for the updated tree and garbage-collect all the nodes you replaced. However, some tree structures have the desirable property that they need to replace no more than O(log N) nodes of the tree on an insertion and can re-use the rest. This means that the rotation of a red-black tree (for example) has not much more overhead than an unbalanced insertion.
Also, you will typically need to query a symbol table much more often than you update it. It therefore becomes less tempting to try to make insertion faster: if you’re inserting, you might as well rebalance.
The question of which self-balancing tree structure is best for a functional language has been asked here, more than once.
Since Davislor already answered your question extensively, here are mostly some implementation hints. I would add that choice of data structure for your symbol table is probably not relevant for a toy compiler. Compilation time only starts to become an issue when you compiler is used on a lot of code and the code is recompiled often.
Sticking to a O(n) insert/lookup data structure is fine in practice until it isn't.
Signature-wise, all you want is a key-value mapping, insert, and lookup:
signature SymTab =
sig
type id
type value
type symtab
val empty : symtab
val insert : id -> value -> symtab -> symtab
val lookup : id -> symtab -> value option
end
A simple O(n) implementation with lists might be:
structure ListSymTab : SymTab =
struct
type id = string
type value = int
type symtab = (id * value) list
val empty = []
fun insert id value [] = [(id, value)]
| insert id value ((id',value')::symtab) =
if id = id'
then (id,value)::symtab
else (id',value')::insert id value symtab
fun lookup _ [] = NONE
| lookup id ((id',value)::symtab) =
if id = id' then SOME value else lookup id symtab
end
You might use it like:
- ListSymTab.lookup "hello" (ListSymTab.insert "hello" 42 ListSymTab.empty);
> val it = SOME 42 : int option
Then again, maybe your symbol table doesn't map strings to integers, or you may have one symbol table for variables and one for functions.
You could parameterise the id/value types using a functor:
functor ListSymTabFn (X : sig
eqtype id
type value
end) : SymTab =
struct
type id = X.id
type value = X.value
(* The rest is the same as ListSymTab. *)
end
And you might use it like:
- structure ListSymTab = ListSymTabFn(struct type id = string type value = int end);
- ListSymTab.lookup "world" (ListSymTab.insert "hello" 42 ListSymTab.empty);
> val it = NONE : int option
All you need for a list-based symbol table is that the identifiers/symbols can be compared for equality. For your balanced-tree symbol table, you need identifiers/symbols to be orderable.
Instead of implementing balanced trees from scratch, look e.g. at SML/NJ's RedBlackMapFn:
To create a structure implementing maps (dictionaries) over a type T [...]:
structure MapT = RedBlackMapFn (struct
type ord_key = T
val compare = compareT
end)
Try this example with T as string and compare as String.compare:
$ sml
Standard ML of New Jersey v110.76 [built: Sun Jun 29 03:29:51 2014]
- structure MapS = RedBlackMapFn (struct
type ord_key = string
val compare = String.compare
end);
[autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[library $SMLNJ-LIB/Util/smlnj-lib.cm is stable]
[autoloading done]
structure MapS : ORD_MAP?
- open MapS;
...
Opening the structure is an easy way to explore the available functions and their types.
We can then create a similar functor to ListSymTabFn, but one that takes an additional compare function:
functor RedBlackSymTabFn (X : sig
type id
type value
val compare : id * id -> order
end) : SymTab =
struct
type id = X.id
type value = X.value
structure SymTabX = RedBlackMapFn (struct
type ord_key = X.id
val compare = X.compare
end)
(* The 'a map type inside SymTabX maps X.id to anything. *)
(* We are, however, only interested in mapping to values. *)
type symtab = value SymTabX.map
(* Use other stuff in SymTabT for empty, insert, lookup. *)
end
Finally, you can use this as your symbol table:
structure SymTab = RedBlackSymTabFn(struct
type id = string
type value = int
val compare = String.compare
end);

Recursive type definition in flow

I'm trying to use flow 0.53.1. Could you please help me explain this weird behavior?
This code sample:
/* #flow */
type AnySupportedType =
| AnySupportedPrimitive
| AnySupportedObject
| AnySupportedArray;
type AnySupportedArray = Array<AnySupportedType>;
type AnySupportedObject = { [string]: AnySupportedType };
type AnySupportedPrimitive = boolean | number | string | void;
type DataID = string
type Data = {
id: DataID
}
const y: Data = { id: "123" }
const x: AnySupportedType = y;
Renders this error:
17: const x: AnySupportedType = y;
^ object type. This type is incompatible with
17: const x: AnySupportedType = y;
^ union: AnySupportedPrimitive | AnySupportedObject | AnySupportedArray
Link to flow.org web-based example to play with.
Actually, this has to do with mutability. Flow cannot allow this code, since you could write x.id = 5 (after the appropriate type refinements), since the AnySupportedType type allows you to set any supported type, including a number as a property.
To solve this, you need to make the object properties covariant, effectively making them read-only:
type AnySupportedObject = { +[string]: AnySupportedType };
Note the addition of the +.
Once you do this, Flow allows the original assignment but prevents you from setting properties on x.
Check out the complete example on try.
See https://flow.org/blog/2016/10/04/Property-Variance/
The answer is that Flow has two ways to type Objects. One, your AnySupportedObject, treats the object as as dictionary where you can find an item by any key (similar to Map<string, whatever>.
The other way is as a record, where there are a specific set of known keys and each key can point to its own type of value (for example, {a: number, b: string}.
Those two types have very different meanings, though often either one can apply to a specific object. The type system keeps them distinct and forces you to treat an object in one way or the other to avoid generating type errors.

How do you get the Discriminated Union Type from a Case instance?

Given these two Discriminated Unions I'd like to get the DeclaringType from a case instance.
type SingleCaseUnion =
| One
type MultiCaseUnion =
| Two
| Three
An example for each case would be as follows:
getDiscriminatedUnionType One = typeof<SingleCaseUnion> // true
getDiscriminatedUnionType Three = typeof<MultiCaseUnion> // true
My first attempt was to get the case type and get it's base class, this works because in F# a subtype is created for each case.
MultiCaseUnion.Two.GetType().BaseType = typeof<MultiCaseUnion> // true
However, for a single case union this doesn't work because no nested types are created.
SingleCaseUnion.One.GetType().BaseType = typeof<SingleCaseUnion> // false
My second attempt, which aimed to get a more robust solution was to use the FSharp Reflection helpers.
FSharpType.GetUnionCases(unionValue.GetType()).First().DeclaringType
This does work for all cases but it has to generate UnionCaseInfo instances for each case which seems somewhat unnecessary.
Is there Something built in that I may have missed? Something like:
FSharpValue.GetUnionFromCase(SingleCaseUnion.One)
How about
open FSharp.Reflection
type FSharpType =
static member GetUnionType t =
let ownType = t.GetType()
assert FSharpType.IsUnion(ownType)
let baseType = ownType.BaseType
if baseType = typeof<System.Object> then ownType else baseType
Test:
(FSharpType.GetUnionType MultiCaseUnion.Three).Name //MultiCaseUnion
(FSharpType.GetUnionType SingleCaseUnion.One).Name //SingleCaseUnion

Resources