Is it possible to make the following example completely polymorphic in F #?

type Mul = Mul with member inline __.Op(a: ^a,b: ^a) = a*b type Div = Div with member inline __.Op(a: ^a,b: ^a) = a/b type Add = Add with member inline __.Op(a: ^a,b: ^a) = a+b type Sub = Sub with member inline __.Op(a: ^a,b: ^a) = ab let inline op xab = (^a: (member Op: ^b * ^b -> ^b) x,a,b) let inline tup2 abcd = op Mul ab, op Mul cd let inline tup2' fabcd = op fab, op fcd let a = tup2 1 2 3.0f 4.0f //let b = tup2' Mul 1 2 3.0f 4.0f //Gives a type error. 

I am wondering if there is a way to make types do what I want in the above example, or if I have finally reached the limit of a system like F #. In fact, there is a way to do the above work, and that should put all the types in one DU, and then map the pattern to the DU type as follows:

 type Operation = | Mul | Add | Sub | Div member inline t.Op ab = match t with | Mul -> a * b | Add -> a + b | Sub -> a - b | Div -> a / b let inline map' (f: Operation) abcd = (f.Op ab, f.Op cd) map' Mul 1 2 3.0f 4.0f 

But assuming that the first example worked, it would be a more dynamic solution. Sorry for something like passing a higher order function by name inside an argument and with it built in place to make it general, impossible.

+4
source share
1 answer

This limitation of most modern types of systems is well explained in kvb's answer to this question .

A hack based workaround is described here. Actually this is very similar to your code, but less verbose.

 type Mul = Mul with static member inline ($) (Mul, a: ^a) = fun (b: ^a) -> a*b type Div = Div with static member inline ($) (Div, a: ^a) = fun (b: ^a) -> a/b type Add = Add with static member inline ($) (Add, a: ^a) = fun (b: ^a) -> a+b type Sub = Sub with static member inline ($) (Sub, a: ^a) = fun (b: ^a) -> ab let inline tup2' fabcd = (f $ a) b, (f $ c) d let b = tup2' Mul 1 2 3.0f 4.0f 

The idea is that instead of defining a function, you determine the type using a single method (which you have already done) in this case it will be an operator that will mean application.

So instead of fx you write f $ x .

UPDATE

As already mentioned, your code is not far from the solution suggested in this answer. Here is a working example that is even closer to your source code:

 type Mul = Mul with static member inline Op(Mul, a: ^a,b: ^a) = a*b type Div = Div with static member inline Op(Div, a: ^a,b: ^a) = a/b type Add = Add with static member inline Op(Add, a: ^a,b: ^a) = a+b type Sub = Sub with static member inline Op(Sub, a: ^a,b: ^a) = ab let inline op xab = ((^a or ^b): (static member Op: ^a * ^b * ^b -> ^b) (x, a, b)) let inline tup2 abcd = op Mul ab, op Mul cd let inline tup2' fabcd = op fab, op fcd let a = tup2 1 2 3.0f 4.0f let b = tup2' Mul 1 2 3.0f 4.0f //Gives NO type error. 

So, basically your source code, but using static methods and using or in restrictions. By doing this, the compiler does not solve the problem earlier and therefore works.

I used the statement because it is less verbose, in which case I like the way it reads, since Haskell $ means application of the function.

+7
source

Source: https://habr.com/ru/post/1261201/


All Articles