F# pattern matching problem? - f#

I have a problem when pattern matching with F#. I'm building an F# library and have this so far:
namespace parser
module parse =
let public y = function
| x when x.Contains("hi") -> "HELLO"
| x when x.Contains("hello") -> "HI"
| x -> x
but it gives me error: Error Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.

Essentially, the compiler doesn't understand that you want the argument to your function to be of type string. Basically, you can NOT invoke instance methods on implicitly declared function arguments. You'll need to use something like the following.
let y (value:string) =
match value when
| x when x.Contains("hi") -> "HELLO"
| x when x.Contains("hello") -> "HI"
| x -> x
Interestingly, if you were not invoking an instance method, but instead using it in some other way (where the type was already known), you would be fine. In other words, suppose a StringUtils module contained a method Has, which took in two strings and performed the same check as Contains; if so, you could use the implicit argument, because the compiler already knows of which type the value must be.
module StringUtils =
let has (word:string) value = word.Contains(value)
module Parse =
let y = function
| x when x |> StringUtils.has "hi" -> "HELLO"
| x when x |> StringUtils.has "hello" -> "HI"
| x -> x
Obviously, in many cases, this sort of thing is unnecessarily verbose. But it demonstrates the larger point about F#'s type inference behavior.

The compiler wants to know the type of x is in your y function so you need to annotate it, like this:
let y (x: string) =
match x with
| x when x.Contains "hi" -> "HELLO"
| x when x.Contains "hello" -> "HI"
| x -> x

Related

'Anonymous type variables are not permitted in this declaration' error when adding parameters to discriminated union cases in F#

So I have some (I'm assuming rather unusual) code which is for building Function Trees. Here's it is right now:
type FunctionTree<'Function> =
| BranchNode of seq<FunctionTree<'Function>>
| Leaf of (a:'Function -> unit) with
member __.Execute() = do a
The expression a:'Function -> unit is what makes the compiler throw a fit, giving me the error 'Anonymous type variables are not permitted in this declaration' and I have no idea why. I've tried adding a variable to the BranchNode, adding (yucky) double parentheses around the expression but nothing seems to have worked.
Answer to the compiler error question
This does not compile...
Leaf of (a:'Function -> unit)
...because discriminated field names can be added to the types of the DU cases, not to the types of the function types in a DU case. In contrast, this compiles...
Leaf of a: ('Function -> unit)
...because the field name a is being used to name the type (Function -> unit).
Additional discussion about the code
However, there is another issue. The member Execute that you are adding is not being added to the Leaf node, as your code implies. It is being added to the entire function tree. Consequently, you will not have access to the label a inside your implementation of Execute. Think of it like this...
type FunctionTree<'Function> =
| BranchNode of seq<FunctionTree<'Function>>
| Leaf of a: ('Function -> unit)
with member __.Execute() = do a
... with the member shifted to the left to clarify that it applies to the entire union, not just the leaf case. That explains why the above code now has a different compiler error... a is not defined. The field name a is used to clarify the instantiation of a Leaf case. The field name a is not available elsewhere.
let leaf = Leaf(a: myFunc)
Consequently, the label a is not available to your Execute member. You would need to do something like this...
with member x.Execute(input) =
match x with
| BranchNode(b) -> b |> Seq.iter(fun n -> n.Execute(input))
| Leaf(f) -> f(input) |> ignore
Notice in the above code that the x value is a FunctionTree.
Alternative implementation
We could continue going. However, I think the following may implement what you are aiming for:
type FunctionTree<'T> =
| BranchNode of seq<FunctionTree<'T>>
| LeafNode of ('T -> unit)
let rec evaluate input tree =
match tree with
| LeafNode(leaf) -> leaf(input)
| BranchNode(branch) -> branch |> Seq.iter (evaluate input)
BranchNode([
LeafNode(printfn "%d")
LeafNode(printfn "%A")
])
|> evaluate 42

Pattern matching with type annotations

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.

Why can't I simplify this iteration through a list of members of a discriminated union?

Frequently one wants to iterate (with either map, iter, or fold) through a collection of heterogeneous objects (different types). One way to deal with this is to create a discriminated union, which allows one to create a list with the objects suitably converted to DU cases. The following code does that in a simple example:
type MYDU = | X1 of int
| X2 of float
| X3 of string
let bar (y: MYDU) =
match y with
| X1 x -> printfn "%A" x
| X2 x -> printfn "%A" x
| X3 x -> printfn "%A" x
[X1(1); X2(2.0); X3("3"); X1(4)]
|> List.map bar |> ignore
This code runs fine and prints
1
2.0
"3"
4
Great! But I wonder if one can avoid repeating the call to printfn. I tried the following and it does not compile:
let baz (y: MYDU) =
match y with
| X1 x | X2 x | X3 x -> printfn "%A" x // red squiggly line under X1 x
The compiler issues this message:
This expression was expected to have type 'int' but here has type 'float'
I suspect avoiding repetition is feasible but I must be making a basic mistake. Any suggestions?
You're not making a mistake there, it's just not something F#'s type system would allow.
You can have multiple patterns on the left side of the match case arrow, but they are required to bind the same set of values (incl. the types). Here, x has a different type for each pattern, and that's enough for the compiler to complain.
There are ways to alleviate the pain (you could have a member on the DU that would return a boxed value, or you could have an active pattern that would do the boxing in the match case), but they're highly situational. Splitting the patterns into separate cases and repeating the right side for each one of them is always a better solution in a vacuum.
Something you could do instead is convert your arguments to a common type for printing, then print that value out instead. And you still get the advantages of pattern matching and discriminated unions :)
Here is an example of this approach
type MYDU =
| X1 of int
| X2 of float
| X3 of string
let bar y =
let myStr =
match y with
| X1 x -> string x
| X2 x -> string x
| X3 x -> x
printfn "%s" myStr
bar (X1 5)
It is possible to avoid this repetition to some degree by "boxing" the values to the obj type. This is an alias for the .NET's System.Object: "the ultimate base class of all classes in the .NET Framework". This means that any value of any type is also an obj.
However, when you box an object you lose static typing. You are subverting the F# type system and increasing the chance of an error. This is why it should generally be avoided unless you have a good reason for doing so.
The function printfn "%A" can take any type so its type signature is effectively obj -> unit. If all you want to do is run this function on the value, then it might be considered reasonable to use boxing. You could define this active pattern, which uses the box function:
let (|Box|) x = box x
And then use the pattern like this:
let printMyDu myDu =
match myDu with
| X1 (Box x)
| X2 (Box x)
| X3 (Box x) -> printfn "%A" x
Again, you should avoid doing this if possible as you are losing type safety in many cases. For example, if you ever box a value only to later check which type the value is, you are probably taking the wrong approach for F#. In this example we box the value x and then immediately use it and discard it, so we don't reduce overall type safety.

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.

F# Higher-order function deciphering

Further to my last question:
let safeInput:Map<'a,'b> option -> 'a -> 'b -> Map<'a,'b> option = fun x y z ->
match x with
| Some d -> Some(d.Add(y,z))
| None -> Some([y,z]|>Map.ofList)
I understand how simple higher-order functions are declared as a type... reading from right to left if '->' is used more than once to decipher what it returns.. i.e. a higher order function.
For the above example from a book... I understand this is adding to a map, I'm just a bit hazy on how the top line should be deciphered? And the use of the 'fun' keyword?
So the first line states that safeInput is a function which takes a Map option a key a value and then returns a map option. The fun keyword is just a way of creating the function.
An equivalent function is
let safeInput (x:Map<'a,'b> option) (y:'a) (z:'b) :Map<'a,'b> option =
match x with
| Some d -> Some(d.Add(y,z))
| None -> Some([y,z]|>Map.ofList)

Resources