Operator overloading for discriminated union - f#

I'm trying to write some numerical code that can work with either scalars or vectors (in this case it's the D and DV types respectively, from DiffSharp). Sometimes I want to be able to use either so I've defined a discriminated union for them:
type IBroadcastable =
| Scalar of D
| Vect of DV
A lot of operators are already overloaded for both of these types, so to use them on IBroadcastable I write add code like this to the union:
static member Exp x =
match x with
| Scalar x -> Scalar (exp x)
| Vect x -> Vect (exp x)
This seems very redundant. Is there any way I can use the operator on the union without having to write a new overload for it? Or I should I be using a different pattern (i.e. not a discriminated union)? An example of what I want to use this type for:
let ll (y: IBroadcastable) (theta: IBroadcastable) = y*theta-(exp theta)
The * and - will have more complicated behaviour (array broadcasting), which it makes sense to have to describe myself, but the exp operator is simple, as above. This needs to be a function since I want to be able to partially apply the y argument, get the gradient with DiffSharp, and maximise it with respect to the theta argument.

Fundamentally, since you're defining an abstraction, you need to define your operations in terms of that abstraction. That's a cost that has to be offset by the convenience it affords you elsewhere in your code.
What you may be wondering is if F# will let you cut on the boilerplate in your particular case. Apart from using the function keyword, not really, because both branches are really doing different things: the type of the bound variable x is different, and you're wrapping them in different union cases. If you were really doing the same thing, you could write it as such, for example:
type DU =
| A of float * float
| B of float * string
with
static member Exp = function
| A (b, _)
| B (b, _) -> exp b // only write the logic once

Your sample function ll is actually even more generic - it can work on anything that supports the operations it uses, even things that are not D or DV. If you define it using inline, then you will be able to call the function on both:
let inline ll y theta = y*theta-(exp theta)
The inline modifier lets F# use static member constraints, which can be satisfied by the required members when calling the function (unlike with normal generic functions that have to be compiled using what .NET runtime provides).
I expect this will not work for all your code, because you will need some operations that are specific to D and DV, but do not have generic F# function such as exp. You can actually access those using static member constraints, though this gets a bit hairy.
Assuming D and DV values both have a member Foo returning string, you can write:
let inline foo (x:^T) =
(^T : (member Foo : string) x)
let inline ll y theta = y*theta-(exp theta)+foo y

You can cut down on the boilerplate by doing something like this:
type IBroadcastable =
| Scalar of D
| Vect of DV
let inline private lift s v = function
| Scalar d -> Scalar (s d)
| Vect dv -> Vect (v dv)
type IBroadcastable with
static member Exp b = lift exp exp b
static member Cos b = lift cos cos b
...
and if you want to support binary operators, you can define a corresponding lift2 - but carefully consider whether it makes sense for the first argument to a binary operator to be a Scalar value and the second to be a Vect (or vice versa) - if not, then your discriminated union might not be an appropriate abstraction.

Related

Is there a name for this higher order function?

I very frequently want to apply the same argument twice to a binary function f, is there a name for this convert function/combinator?
// convert: f: ('a -> 'a -> 'b) -> 'a -> 'b
let convert f x = f x x
Example usage might be partially applying convert with the multiplication operator * to fix the multiplicand and multiplier:
let fixedMultiplication = convert (*)
fixedMultiplication 2 // returns 4
That combinator is usually called a warbler; the name comes from Raymond Smullyan's book To Mock a Mockingbird, which has a bunch of logic puzzles around combinator functions, presented in the form of birds that can imitate each other's songs. See this usage in Suave, and this page which lists a whole bunch of combinator functions (the "standard" ones and some less-well-known ones as well), and the names that Smullyan gave them in his book.
Not really an answer to what it's called in F#, but in APL or J, it's called the "reflexive" (or perhaps "reflex") operator. In APL it is spelt ⍨ and used monadically – i.e. applied to one function (on its left). In J it's called ~, and used in the same way.
For example: f⍨ x is equivalent to x f x (in APL, functions that take two arguments are always used in a binary infix fashion).
So the "fixedMultiplication" (or square) function is ×⍨ in APL, or *~ in J.
This is the monadic join operator for functions. join has type
Monad m => m (m a) => m a
and functions form a monad where the input type is fixed (i.e. ((->) a), so join has type:
(a -> (a -> b)) -> (a -> b)

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.

Performing Calculations on F# option types

I'm trying to write some function that handle errors by returning double options instead of doubles. Many of these functions call eachother, and so take double options as inputs to output other double options. The problem is, I can't do with double options what I can do with doubles--something simple like add them using '+'.
For example, a function that divides two doubles, and returns a double option with none for divide by zero error. Then another function calls the first function and adds another double option to it.
Please tell me if there is a way to do this, or if I have completely misunderstood the meaning of F# option types.
This is called lifting - you can write function to lift another function over two options:
let liftOpt f o1 o2 =
match (o1, o2) with
| (Some(v1), Some(v2)) -> Some(f v1 v2)
| _ -> None
then you can supply the function to apply e.g.:
let inline addOpt o1 o2 = liftOpt (+) o1 o2
liftA2 as mentioned above will provide a general way to 'lift' any function that works on the double arguments to a function that can work on the double option arguments.
However, in your case, you may have to write special functions yourself to handle the edge cases you mention
let (<+>) a b =
match (a, b) with
| (Some x, Some y) -> Some (x + y)
| (Some x, None) -> Some (x)
| (None, Some x) -> Some (x)
| (None, None) -> None
Note that liftA2 will not put the cases where you want to add None to Some(x) in automatically.
The liftA2 method for divide also needs some special handling, but its structure is generally what we would write ourselves
let (</>) a b =
match (a, b) with
| (Some x, Some y) when y <> 0.0d -> Some (x/y)
| _ -> None
You can use these functions like
Some(2.0) <+> Some(3.0) // will give Some(5.0)
Some(1.0) </> Some(0.0) // will give None
Also, strictly speaking, lift is defined as a "higher order function" - something that takes a function and returns another function.
So it would look something like this:
let liftOpt2 f =
(function a b ->
match (a, b) with
| (Some (a), Some (b)) -> f a b |> Some
| _ -> None)
In the end, I realized what I was really looking for was the Option.get function, which simply takes a 'a option and returns an 'a. That way, I can pattern match, and return the values I want.
In this case you might want to consider Nullables over Options, for two reasons:
Nullables are value types, while Options are reference types. If you have large collections of these doubles, using Nullables will keep the numbers on the stack instead of putting them on the heap, potentially improving your performance.
Microsoft provides a bunch of built-in Nullable Operators that do let you directly perform math on nullables, exactly as you're trying to do with options.

constrain generic type to inherit a generic type in f#

let mapTuple f (a,b) = (f a, f b)
I'm trying to create a function that applies a function f to both items in a tuple and returns the result as a tuple. F# type inference says that mapTuple returns a 'b*'b tuple. It also assumes that a and b are of the same type.
I want to be able to pass two different types as parameters. You would think that wouldn't work because they both have to be passed as parameters to f. So I thought if they inherited from the same base class, it might work.
Here is a less generic function for what I am trying to accomplish.
let mapTuple (f:Map<_,_> -> Map<'a,'b>) (a:Map<int,double>,b:Map<double, int>) = (f a, f b)
However, it gives a type mismatch error.
How do I do it? Is what I am trying to accomplish even possible in F#?
Gustavo is mostly right; what you're asking for requires higher-rank types. However,
.NET (and by extension F#) does support (an encoding of) higher-rank types.
Even in Haskell, which supports a "nice" way of expressing such types (once you've enabled the right extension), they wouldn't be inferred for your example.
Digging into point 2 may be valuable: given map f a b = (f a, f b), why doesn't Haskell infer a more general type than map :: (t1 -> t) -> t1 -> t1 -> (t, t)? The reason is that once you include higher-rank types, it's not typically possible to infer a single "most general" type for a given expression. Indeed, there are many possible higher-rank signatures for map given its simple definition above:
map :: (forall t. t -> t) -> x -> y -> (x, y)
map :: (forall t. t -> z) -> x -> y -> (z, z)
map :: (forall t. t -> [t]) -> x -> y -> ([x], [y])
(plus infinitely many more). But note that these are all incompatible with each other (none is more general than another). Given the first one you can call map id 1 'c', given the second one you can call map (\_ -> 1) 1 'c', and given the third one you can call map (\x -> [x]) 1 'c', but those arguments are only valid with each of those types, not with the other ones.
So even in Haskell you need to specify the particular polymorphic signature you want to use - this may be a bit of a surprise if you're coming from a more dynamic language. In Haskell, this is relatively clean (the syntax is what I've used above). However, in F# you'll have to jump through an additional hoop: there's no clean syntax for a "forall" type, so you'll have to create an additional nominal type instead. For example, to encode the first type above in F# I'd write something like this:
type Mapping = abstract Apply : 'a -> 'a
let map (m:Mapping) (a, b) = m.Apply a, m.Apply b
let x, y = map { new Mapping with member this.Apply x = x } (1, "test")
Note that in contrast to Gustavo's suggestion, you can define the first argument to map as an expression (rather than forcing it to be a member of some separate type). On the other hand, there's clearly a lot more boilerplate than would be ideal...
This problem has to do with rank-n types which are supported in Haskell (through extensions) but not in .NET type system.
One way I found to workaround this limitation is to pass a type with a single method instead of a function and then define an inline map function with static constraints, for example let's suppose I have some generic functions: toString and toOption and I want to be able to map them to a tuple of different types:
type ToString = ToString with static member inline ($) (ToString, x) = string x
type ToOption = ToOption with static member ($) (ToOption, x) = Some x
let inline mapTuple f (x, y) = (f $ x, f $ y)
let tuple1 = mapTuple ToString (true, 42)
let tuple2 = mapTuple ToOption (true, 42)
// val tuple1 : string * string = ("True", "42")
// val tuple2 : bool option * int option = (Some true, Some 42)
ToString will return the same type but operating with arbitrary types. ToOption will return two Generics of different types.
By using a binary operator type inference creates the static constraints for you and I use $ because in Haskell it means apply so a nice detail is that for haskellers f $ x reads already apply x to f.
At the risk of stating the obvious, a good enough solution might be to have a mapTuple that takes two functions instead of one:
let mapTuple fa fb (a, b) = (fa a, fb b)
If your original f is generic, passing it as fa and fb will give you two concrete instantiations of the function with the types you're looking for. At worst, you just need to pass the same function twice when a and b are of the same type.

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

Resources