Extension operator in F# - f#

Disclaimer: I am very new to F#.
I created a custom type for which I have an addition function. I wanted to extend it to allow addition with the standard + operator (the type is simplified for conciseness):
type MyInt = {N:int}
let sumMyInt n1 n2 = {N=n1.N + n2.N}
type MyInt with
static member (+)(n1, n2) = sumMyInt n1 n2
let n1 = {N=1}
let n2 = {N=2}
printfn "%O" (n1 + n2)
This works and prints {N=3}. I wanted to lift this operation to lists of MyInt, and if I understand the MSDN docs correctly extending MyInt list requires extension methods. So I write:
open System.Collections.Generic
open System.Runtime.CompilerServices
let sumMyInts = List.map2 sumMyInt
[<Extension>]
type MyIntListExtensions =
[<Extension>]
static member inline (+)(ss1, ss2) = sumMyInts ss1 ss2
[<Extension>]
static member inline SumMyInts (ss1, ss2) = sumMyInts ss1 ss2
let x = sumMyInts ns1 ns2
let y = ns1.SumMyInts ns2
let z = ns1 + ns2
Now x and y compile and work. z refuses to compile with error:
The type 'MyInt list' does not support the operator '+'
The most surprising part is that this compiles:
let z' = ns1.op_Addition ns2
Am I doing something wrong? How can I define an extension operator?

You cannot do what you want to today in F#, see this RFC.
What you could do is create a global operator that does this:
let inline (#+) (xs: 'a list) (ys: 'a list) =
List.map2 (+) xs ys
> [1; 2] #+ [3; 4]
- ;;
val it : int list = [4; 6]
Explicitly not shadowing (+) here for obvious reasons :).
More about creating operators here: https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/operator-overloading#creating-new-operators

Related

How to constrain type parameter must be an algebraic type (int, float, BigInteger, BigRational, ...)

-- While there are some questions on the net wrt. type constraints already, I didn't find one that can help me solving my issue. --
Goal: I want to create my own Vector/Matrix types, but so, that the implementation does not lock in to a speicific BigRational (or alike) type. All I'd prefer to require is the standard algebraic operations on such types (+ - * / % equality).
open System
type Foo<'T> (value: 'T) =
member inline __.Value : 'T = value
static member inline Add (a: Foo<'T>) (b: Foo<'T>) =
Foo<'T>(a.Value + b.Value)
module Foo =
let inline Create (v) = Foo(v)
let log (foo: #Foo<_>) =
printfn "Foo: %s" (foo.Value.ToString())
[<EntryPoint>]
let main argv =
Foo.log (Foo.Create("hi ho"))
Foo.log (Foo<int>(31415))
Foo.log (Foo<float>(3.1415))
Foo.log (Foo<int>.Add (Foo.Create(3)) (Foo.Create(4)))
let a = Foo.Create(13)
let b = Foo.Create(3.1415)
Foo.log (Foo<int>.Add (a.Value) (a.Value))
Foo.log (Foo<float>.Add (b.Value) (b.Value))
0 // return an integer exit code
I cannot get this tiny example code to compile for more than one single type, such as Foo<int> as well as Foo<float>. How could I do it right?
Many thanks in advance,
Christian.
You almost have it, actually.
In order to create a function that accepts any type that has a + operator, this function must have statically-resolved type parameters (SRTP). For this, it must be inline, which your Add is so that's ok. However here Add is not a generic method: it's a method on the generic type Foo<'T>, so it receives its 'T parameter from it. And a type cannot have SRTP.
A simple fix is to move Add from being a method on the type Foo<'T> to being a function in the module Foo. Then it will become actually generic.
open System
type Foo<'T> (value: 'T) =
member inline __.Value : 'T = value
module Foo =
let inline Create (v) = Foo(v)
let inline Add (a: Foo< ^T>) (b: Foo< ^T>) =
Foo< ^T>(a.Value + b.Value)
let log (foo: #Foo<_>) =
printfn "Foo: %s" (foo.Value.ToString())
[<EntryPoint>]
let main argv =
Foo.log (Foo.Create("hi ho"))
Foo.log (Foo<int>(31415))
Foo.log (Foo<float>(3.1415))
Foo.log (Foo.Add (Foo.Create(3)) (Foo.Create(4)))
let a = Foo.Create(13)
let b = Foo.Create(3.1415)
Foo.log (Foo.Add a a)
Foo.log (Foo.Add b b)
0
I think all you need is the inline keyword if you just want to propagate the member constraints of F#'s overloaded arithmetic operators.
type Foo<'T> (value : 'T) =
member __.Value = value
static member inline (+) (a : Foo<_>, b : Foo<_>) = Foo(a.Value + b.Value)
// static member
// ( + ) : a:Foo< ^a> * b:Foo< ^b> -> Foo< ^c>
// when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
Now you can add two Foos of the same type that support a static member (+), Foo 3 + Foo 4 or Foo 3.14 + Foo 3.14, even Foo(Foo 3) + Foo(Foo 4); but not Foo 3 + Foo 3.14. You may still instantiate types that do not possess such member.

How to declare a generic conversion operator that preserves units of measure?

The built-in conversion operators in F# eliminate units of measure. I'd like to define ones that preserve them. I can do it fine for one specific conversion, e.g. int to float:
let inline intToFloat (x:int<'u>) =
x |> float |> LanguagePrimitives.FloatWithMeasure<'u>
But I don't know what would be the syntax for a generic ((anything with an op_Implicit ^m -> float) -> float) operator:
let inline floatM (x:^m<'u>) =
x |> float |> LanguagePrimitives.FloatWithMeasure<'u>
// FS0712: Type parameter cannot be used as type constructor
Is it possible at all to do this?
I did it as such:
let inline toIntWithMeasure<[<Measure>] 'a> (x:obj) =
match x with
| :? int as i -> i |> LanguagePrimitives.Int32WithMeasure<'a>
| _ -> failwith "Not an int!"
A workaround is to use overloading rather than generics:
type Conv =
static member inline toDouble<[<Measure>] 'u> (x: float32<'u>) =
x |> float |> LanguagePrimitives.FloatWithMeasure<'u>
static member inline toDouble<[<Measure>] 'u> (x: sbyte<'u>) =
x |> float |> LanguagePrimitives.FloatWithMeasure<'u>
static member inline toDouble<[<Measure>] 'u> (x: int16<'u>) =
x |> float |> LanguagePrimitives.FloatWithMeasure<'u>
static member inline toDouble<[<Measure>] 'u> (x: int<'u>) =
x |> float |> LanguagePrimitives.FloatWithMeasure<'u>
static member inline toDouble<[<Measure>] 'u> (x: int64<'u>) =
x |> float |> LanguagePrimitives.FloatWithMeasure<'u>
And now:
let f = Conv.toDouble (45<second>) // f is a float<second>
I'd love to be able to declare an operator to hide away the static class, something like:
let inline floatM< ^m, [<Measure>]'u when (^m) : (static member toFloat: ^m<'u> -> float<'u>)> (x:^m) =
Conv.toDouble x
But that still runs into the same limitation that a generic type cannot have a generic unit of measure.
I'll accept my own answer until someone comes up with a better solution.

Error on Extension Methods when Inlining

I want to extend some system types and later use them via inlining
type System.String with
member this.foo n = this + "!" + n
type System.Boolean with
member this.foo n = sprintf "%A!%A" this n
Now I call these extension methods
let x = "foo".foo "bar"
let y = true.foo "bar"
which gives me this
- val x : System.String = "foobar"
- val y : string = "true!"bar""
All fine and dandy - but now I want to wrap the call to .foo into an inline function
let inline foo n v = (^T : (member foo : ^N -> ^S) v, n)
let z = foo "bar" "baz"
Only now I get a compiler error telling me that
> The type 'string' does not support the operator 'foo':
well ... it does!
Can somebody explain whats going on?
Extension methods are not taken into account in static member constraints (possible duplicate of this) and this is a general problem when you want to implement generic code using member constraints and make it work also with already defined or primitive types.
See the user voice request, also the workarounds mentioned here and Don Syme's explanation of why it's complicated to implement it in the F# compiler.
If you follow the links there you will see currently the way to workaround it basically involves creating an intermediate type and overloads for all the known types and a generic one for the extensions.
This is a very basic example of how to workaround it:
type Foo = Foo with
static member ($) (Foo, this:int) = fun (n:int) -> this + n
static member ($) (Foo, this:string) = fun n -> this + "!" + n
static member ($) (Foo, this:bool) = fun n -> sprintf "%A!%A" this n
let inline foo this n = (Foo $ this) n
//Now you can create your own types with its implementation of ($) Foo.
type MyType() =
static member ($) (Foo, this) =
fun n -> printfn "You called foo on MyType with n = %A" n; MyType()
let x = foo "hello" "world"
let y = foo true "world"
let z = foo (MyType()) "world"
You can enhance it by adding an explicit generic overload for new types:
// define the extensions
type System.String with
member this.foo n = this + "!" + n
type System.Boolean with
member this.foo n = sprintf "%A!%A" this n
// Once finished with the extensions put them in a class
// where the first overload should be the generic version.
type Foo = Foo with
static member inline ($) (Foo, this) = fun n -> (^T : (member foo : ^N -> ^S) this, n)
static member ($) (Foo, this:string) = fun n -> this.foo n
static member ($) (Foo, this:bool) = fun n -> this.foo n
// Add other overloads
static member ($) (Foo, this:int) = fun n -> this + n
let inline foo this n = (Foo $ this) n
//later you can define any type with foo
type MyType() =
member this.foo n = printfn "You called foo on MyType with n = %A" n; MyType()
// and everything will work
let x = foo "hello" "world"
let y = foo true "world"
let z = foo (MyType()) "world"
You can further refine it by writing the static constraints by hand and using a member instead of an operator (see an example here),
At the end of the day you will end up with something like this generic append function from FsControl.
Statically resolved type constraints do not support extension methods. It's just not a feature of F#.
If you would like F# to gain support for higher-kinded polymorphism, you can vote for it on user voice.

Extension method with F# function type

The MSDN doc on Type Extensions states that "Before F# 3.1, the F# compiler didn't support the use of C#-style extension methods with a generic type variable, array type, tuple type, or an F# function type as the “this” parameter." (http://msdn.microsoft.com/en-us/library/dd233211.aspx)
How can be a Type Extension used on F# function type? In what situations would such a feature be useful?
Here is how you can do it:
[<Extension>]
type FunctionExtension() =
[<Extension>]
static member inline Twice(f: 'a -> 'a, x: 'a) = f (f x)
// Example use
let increment x = x + 1
let y = increment.Twice 5 // val y : int = 7
Now for "In what situations would such a feature be useful?", I honestly don't know and I think it's probably a bad idea to ever do this. Calling methods on a function feels way too JavaScript-ey, not idiomatic at all in F#.
You may simulate the . notation for extension methods with F#'s |> operator. It's a little clumsier, given the need for brackets:
let extension f x =
let a = f x
a * 2
let f x = x*x
> f 2;;
val it : int = 4
> (f |> extension) 2;;
val it : int = 8
> let c = extension f 2;; // Same as above
val c : int = 8

F# Checked Arithmetics Scope

F# allows to use checked arithmetics by opening Checked module, which redefines standard operators to be checked operators, for example:
open Checked
let x = 1 + System.Int32.MaxValue // overflow
will result arithmetic overflow exception.
But what if I want to use checked arithmetics in some small scope, like C# allows with keyword checked:
int x = 1 + int.MaxValue; // ok
int y = checked { 1 + int.MaxValue }; // overflow
How can I control the scope of operators redefinition by opening Checked module or make it smaller as possible?
You can always define a separate operator, or use shadowing, or use parens to create an inner scope for temporary shadowing:
let f() =
// define a separate operator
let (+.) x y = Checked.(+) x y
try
let x = 1 +. System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
// shadow (+)
let (+) x y = Checked.(+) x y
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
// shadow it back again
let (+) x y = Operators.(+) x y
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
// use parens to create a scope
(
// shadow inside
let (+) x y = Checked.(+) x y
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
)
// shadowing scope expires
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
f()
// output:
// exception
// ran ok
// exception
// ran ok
// exception
// ran ok
Finally, see also the --checked+ compiler option:
http://msdn.microsoft.com/en-us/library/dd233171(VS.100).aspx
Here is a complicated (but maybe interesting) alternative. If you're writing something serious then you should probably use one of the Brians suggestions, but just out of curiosity, I was wondering if it was possible to write F# computation expression to do this. You can declare a type that represents int which should be used only with checked operations:
type CheckedInt = Ch of int with
static member (+) (Ch a, Ch b) = Checked.(+) a b
static member (*) (Ch a, Ch b) = Checked.(*) a b
static member (+) (Ch a, b) = Checked.(+) a b
static member (*) (Ch a, b) = Checked.(*) a b
Then you can define a computation expression builder (this isn't really a monad at all, because the types of operations are completely non-standard):
type CheckedBuilder() =
member x.Bind(v, f) = f (Ch v)
member x.Return(Ch v) = v
let checked = new CheckedBuilder()
When you call 'bind' it will automatically wrap the given integer value into an integer that should be used with checked operations, so the rest of the code will use checked + and * operators declared as members. You end up with something like this:
checked { let! a = 10000
let! b = a * 10000
let! c = b * 21
let! d = c + 47483648 // !
return d }
This throws an exception because it overflows on the marked line. If you change the number, it will return an int value (because the Return member unwraps the numeric value from the Checked type). This is a bit crazy technique :-) but I thought it may be interesting!
(Note checked is a keyword reserved for future use, so you may prefer choosing another name)

Resources