Pattern matching with type annotations - f#

At https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching#tuple-pattern, there is this example of a pattern with a type annotation:
Patterns can have type annotations. These behave like other type annotations and guide inference like other type annotations. Parentheses are required around type annotations in patterns. The following code shows a pattern that has a type annotation.
let detect1 x =
match x with
| 1 -> printfn "Found a 1!"
| (var1 : int) -> printfn "%d" var1
detect1 0
detect1 1
The type annotation (var1 : int) is redundant because the literal 1 in the previous pattern establishes the type unambiguously.
Is there any case in which a type annotation such as this would be useful?

Actually, even when you use type annotation in function parameters, you are using type annotation in patterns too. F# pattern matching works even on function parameters (let binding in general).
So, as usual, type annotation is useful when we want to enforce the type immediately instead of relying on the type inference. We can have many places to put type annotation to achieve the same result. Just choose the place that is most convenient for the situation. Consider example below:
let detect2 (x : int option) =
match x with
| Some y -> ...
| None -> ...
We can write shorter:
let detect2 x =
match x with
| Some (y : int)
| None -> ...
In this situation we should prefer the later one.

Related

Rewriting Erlang in F#

I have found a presentation by Don Syme which shows that Erlang's
fac(0) -> 1
fac(N) -> N * fac(N-1).
is equivalent to F#'s
let rec fac = function
| 0 -> 1
| n -> n * fac (n-1)
But it looks like there is no way to use pattern matching for a different arity without losing type safety. E.g. one could use a list pattern matching, but then a type must be a common base type (such as object):
let concat = function
| [x;y] -> x.ToString() + y.ToString()
| [x] -> x.ToString()
Given that F# functions in modules do not support overloads, it looks like the only way to rewrite Erlang code into F# with static typing is to use static classes with method overloading instead of modules. Is there a better way to rewrite Erlang functions with different arity in F#?
In general, is it correct to say that Erlang's argument matching is closer to .NET's (including C#) method overloading rather than to F#'s pattern matching? Or there is no direct replacement between the two, e.g. there could be a function in Erlang with different arities + a guard:
max(x) -> x.
max(x,y) when x > y -> x.
max(x,y) -> y.
max(comparer, x, y) -> if comparer(x,y) > 0 -> x; true -> y end.
In the last case the arguments are of different types. How would you rewrite it in F#?
You can achieve something close to overloading by rethinking the problem slightly. Instead of thinking about the function as the axis of variability, think of the input as the variable part. If you do that, you'll realise that you can achieve the same with a discriminated union.
Here's a more contrived example than the one in the linked article:
type MyArguments = One of int | Two of int * int
let foo = function
| One x -> string x
| Two (x, y) -> sprintf "%i%i" x y
Usage:
> foo (One 42);;
val it : string = "42"
> foo (Two (13, 37));;
val it : string = "1337"
Obviously, instead of defining such a 'stupid' type as the above MyArguments, you'd define a discriminated union that makes sense in the domain you're modelling.

How encode in a dictionary multiple functions of different types

I'm building a interpreter in F#. I'm trying to be clever and generalize the interpretation of primitive operators as function calls (in this case, as reductions).
This is the idea:
let reduce fx values =
Array.reduce values fx
let primitivesEnv =
let r = Dictionary<string,'T -> 'T -> 'T>()
r.["int_+"] <- reduce (fun(l:int, r:int) -> l + r)
r.["int_-"] <- reduce (fun(l:int, r:int) -> l - r)
r
So I could later do this:
env.["int_+"]([| 1, 2 |])
Of course, the type-checker reject this with
Warning FS0064: This construct causes code to be less generic than
indicated by the type annotations. The type variable 'T has been
constrained to be type ''a -> 'a -> 'a'. Error FS0001: Type mismatch.
Expecting a ('a -> 'a -> 'a) -> ('a -> 'a -> 'a) -> 'a -> 'a -> 'a
but given a ('a -> 'a -> 'a) -> 'a The resulting type would
be infinite when unifying ''a' and '('a -> 'a -> 'a) -> 'a -> 'a ->
'a'
P.D: I know how do this as a simple interpreter, but trying to build a solution that let me build dozens of methods in a generic way, without make a MATCH for each one.
First of all, there are some issues with your code. You have added a type annotation to your dictionary of 'T -> 'T -> 'T but it seems to me that it should return a function of type 'T[] -> 'T since you are trying to give it an array and evaluate a reduction.
Also, [| 1, 2 |] is an array of one tuple, you need an array of multiple values, such as this one : [| 1; 2 |]
I fixed your code like this:
let reduce values =
Array.reduce values
let primitivesEnv =
let r = System.Collections.Generic.Dictionary<string,'T[] ->'T>()
r.["int_+"] <- reduce ((+) : int -> int -> int)
r.["int_-"] <- reduce ((-) : int -> int -> int)
r
let result = primitivesEnv.["int_+"] [| 1; 2 |]
Unfortunately, this isn't the end of the problems.
We might have said that the dictionary is of type 'T[] ->'T but it isn't, the only valid type for the dictionary is int[] -> int, the first int -> int -> int type annotation creates that constraint. If we leave out that type annotation, 'T is constrained to int when we use it with an int[].
The type parameter 'T must always be resolved to a fixed type in some way, it isn't a wild card that lets you use anything.
This means that the dictionary approach is fine until you want to add float (or some other type) in addition to just int. Your only option, when using a dictionary, is to either choose one type or throw away some of your type-safety and resolve the specific type at runtime.
The simplest change to do that would be to create some union cases to describe the different reduction types:
type Reduction =
|IntReduction of (int[] -> int)
|FloatReduction of (float[] -> float)
You then create a Dictionary<string, Reduction> instead of a Dictionary<string,'T[] ->'T>.
When it comes to the more general problem of creating an interpreter in F#, I would start by creating a structured set of discriminated unions to describe the expressions and structure of the mini-language you wish to interpret, this is called an Abstract Syntax Tree (AST).
You can then define a run function that walks the tree and performs all the computations described by the AST.
I would also use a parser combinator library (I'd recommend FParsec) to parse whatever structured text into an abstract syntax tree of the union cases you defined in the step above.
Phillip Trelford has an example online of how to do this using FParsec for a simple C# AST: http://www.fssnip.net/lf This is probably far more powerful than what you need but hopefully it'll give you a starting point.

Hashtable in F#

Is there an alternative to System.Collections.Generic.Dictionary or System.Collections.Hashtable?
I'm unhappy with the former because it returns value using byref, i.e., I need to do the annoying
let x = ref ""
if hashtable.TryGetValue (key, x) then
// Found, value in !x
else
// Not found.
I'm unhappy with the latter because it's not generic.
EDIT. I'd prefer something generic syntactically looking like Map.tryFind, i.e.,
match Hashtable.tryFind k hashtable with
| None -> ... // Not found
| Some v -> ... // Found v.
Out parameters are part of living with the .NET framework. F# does minimize the pain, however, by automatically tuplizing them along with the return value. So, using Dictionary<_,_> you can do:
match d.TryGetValue(key) with
| true, x -> ... //tuple of return value and out parameter
| _ -> ...
See Passing by Reference on MSDN.
You could easily wrap that into an extension:
type System.Collections.Generic.Dictionary<'K, 'V> with
member x.TryFind(key) =
match x.TryGetValue(key) with
| true, v -> Some v
| _ -> None
There are two collection types in F# you should look at:
Collections.Set<'T> Class (F#)
Immutable sets based on binary trees, where comparison is the F#
structural comparison function, potentially using implementations of
the IComparable interface on key values.
Collections.Map<'Key,'Value> Class (F#)
Immutable maps. Keys are ordered by F# generic comparison.
Map has a function you're looking for:
Map.TryFind
Lookup an element in the map, returning a Some value if the element
is in the domain of the map and None if not.

what is use cases of F# explicit type parameters?

As I know, explicit type parameters in value definitions is a one way to overcome "value restriction" problem.
Is there another cases when I need to use them?
Upd: I mean "explicitly generic constructs", where type parameter is enclosed in angle brackets, i.e.
let f<'T> x = x
Polymorphic recursion is another case. That is, if you want to use a different generic instantiation within the function body, then you need to use explicit parameters on the definition:
// perfectly balanced tree
type 'a PerfectTree =
| Single of 'a
| Node of ('a*'a) PerfectTree
// need type parameters here
let rec fold<'a,'b> (f:'a -> 'b) (g:'b->'b->'b) : 'a PerfectTree -> 'b = function
| Single a -> f a
| Node t -> t |> fold (fun (a,b) -> g (f a) (f b)) g
let sum = fold id (+)
let ten = sum (Node(Node(Single((1,2),(3,4)))))
This would likely be rare, but when you want to prevent further generalization (ยง14.6.7):
Explicit type parameter definitions on value and member definitions can affect the process of type inference and generalization. In particular, a declaration that includes explicit generic parameters will not be generalized beyond those generic parameters. For example, consider this function:
let f<'T> (x : 'T) y = x
During type inference, this will result in a function of the following type, where '_b is a type inference variable that is yet to be resolved.
f<'T> : 'T -> '_b -> '_b
To permit generalization at these definitions, either remove the explicit generic parameters (if they can be inferred), or use the required number of parameters, as the following example shows:
let throw<'T,'U> (x:'T) (y:'U) = x
Of course, you could also accomplish this with type annotations.
Most obvious example: write a function to calculate the length of a string.
You have to write:
let f (a:string) = a.Length
and you need the annotation. Without the annotation, the compiler can't determine the type of a. Other similar examples exist - particularly when using libraries designed to be used from C#.
Dealing with updated answer:
The same problem applies - string becomes A<string> which has a method get that returns a string
let f (a:A<string>) = a.get().Length

Active pattern broken in F# 3.0

This active pattern compiles with F# 2.0:
let (|Value|_|) value = // 'a -> 'T option
match box value with
| :? 'T as x -> Some x
| _ -> None
but, in F# 3.0, emits the error:
Active pattern '|Value|_|' has a result type containing type variables that are not determined by the input. The common cause is a [sic] when a result case is not mentioned, e.g. 'let (|A|B|) (x:int) = A x'. This can be fixed with a type constraint, e.g. 'let (|A|B|) (x:int) : Choice = A x'
I tried:
let (|Value|_|) value : 'T option = ...
and:
let (|Value|_|) (value: 'U) = ...
How can it be fixed?
Environments: Visual Studio 2012 (RTM) and FSI v11.0.50727.1
EDIT: Here's a simpler repro:
let (|X|) x = unbox x
There was a bug in the F# 2.0 compiler where the compiler did incorrect analysis and bad code generation for certain Active Patterns with free type variables in the result; a simple repro is
let (|Check|) (a : int) = a, None
//let (|Check|) (a : int) = a, (None : int option)
let check a =
match a with
| Check (10, None) -> System.Console.WriteLine "10"
| Check (20, None) -> System.Console.WriteLine "20"
check 10
check 20
which generates a weird warning at compile-time and compiles into seemingly incorrect code. I am guessing that our attempt to fix this bug (and restrict some crazy cases) in F# 3.0 also broke some legal code as collateral damage of the fix.
I'll file another bug, but for F# 3.0, it sounds like you'll need to use one of the workarounds mentioned in other answers.
I did not install the new version yet, but I agree this looks a bit fishy. I guess there may be a good reason for this restriction, but your example in the other question seems quite compeling.
As a workaround, I think that adding a witness parameter (that is not used, but hints what the type of the result is going to be) could work:
let (|Value|_|) (witness:unit -> 'T) value : 'T option =
match box value with
| :? 'T as x -> Some x
| _ -> None
Of course, this makes the use a bit uglier, because you need to come up with some argument. In the above, I used witness of type unit -> 'T, hoping that the following might compile:
let witness () : 'T = failwith "!"
match box 1 with
| Value witness 1 -> printfn "one"
If that does not work, then you can probably try using witness parameter of type 'T (but then you have to provide an actual function, rather than just a generic function).
for the sake of completeness, one more workaround:
type Box<'R> = Box of obj
let (|Value|_|) ((Box x) : Box<'R> ) : 'R option =
match x with
| :? 'R as x -> Some x
| _ -> None
let check t =
match Box t with
| Value 1 -> printfn "one"
| Value 2 -> printfn "two"
check 1 // one
check 2 // two
however it still will suffer from the problem mentioned by #kvb in another thread. Personally I'll prefer #kvb's version with parameterized active pattern.
See my answer to your other question for some thoughts on how to work around the issue and one reason that such active patterns might be undesirable. I'm not sure whether the breaking change was intended.

Resources