F # Type parameter no restriction

I am trying to define a general addition operator for a wrapper class. So far I have this: (simplified from actual code)

type Wrap<'a> = | Wrap of 'a static member inline (+) (Wrap x, Wrap y) = Wrap (x + y) let inline addSelf x = x + x 

and really works:

 let i = addSelf (Wrap 1) // returns Wrap 2 let f = addSelf (Wrap 1.) // returns Wrap 2.0 

but the following alternative addSelf does not compile

 let inline addSelf' (Wrap x) = (Wrap x) + (Wrap x) // compile error 

gives error FS0193: the type parameter has no restriction 'when (^ a or ^ 15169): (static member (+): ^ a * ^? 15169 β†’ ^? 15170)'

Why doesn't the more limited addSelf work when addSelf works fine? Thank!

+3
generics f # type-constraints type-parameter
Jul 27 '11 at 18:46
source share
4 answers

If you look at the definition of Wrap in FSI, you will see that the static (+) operator is defined only for types that support the restriction, but Wrap itself is defined for any type.

When writing the first version, type inference adds this restriction for you ... but your second version allows any type for x (even for x that does not support static (+)).

those. the second version assumes that you can write a function that supports any type of Wrap <'T>, although there is no guarantee that T supports the + operator.

edit: As Thomas pointed out, this is possible, but you should use special syntax that determines which member to invoke, the following works:

 let inline addSelf (x : Wrap<_>) = ((^a or ^b): (static member (+) : ^a * ^b -> ^c) (x,x)) 
+3
Jul 27 2018-11-21T00:
source share
β€” -

As I said in a comment, I think this is a mistake. Here are my thoughts. When the compiler sees

 let inline addSelf (Wrap x) = (Wrap x) + (Wrap x) 

I think that he should draw approximately the following conclusions:

  • The argument is of type Wrap< ^t> for some new ^t .
  • Therefore, x is of type ^t .
  • Thus, the operands on the right side are also of type Wrap< ^t> .
  • These values ​​are passed to the (+) operator. Therefore, Wrap< ^t> must support a static operator (+) type Wrap< ^t> * Wrap< ^t> -> ^u for some new type ^u .
  • The only static operator (+) defined on Wrap<_> is of type Wrap< ^a> * Wrap< ^b> -> Wrap< ^c> when (^a or ^b) : (static member (+) : ^a * ^b -> ^c .
  • Combining type variables, the general addSelf type must be addSelf : Wrap< ^t> -> Wrap< ^c> when ^t : (static member (+) : ^t * ^t -> ^c)

The various steps of type inference are complex, so it is certainly possible that I missed something, and this behavior is expected. On the other hand, the various steps of type inference are complex, so they are a bit wrong :). This also applies to the fact that you cannot annotate a function and all subexpressions and get the code to compile:

 let inline doStuff< ^t, ^u when ^t : (static member (+) : ^t * ^t -> ^u)> ((Wrap x) : Wrap< ^t>) : Wrap< ^u> = ((Wrap x) : Wrap< ^t>) + ((Wrap x) : Wrap< ^t>) 

You still get a compiler error with a mysterious reference to fresh parameters like ^?12020 and ^?12021 (or any unique ints in your case). I think this should not be.

+4
Jul 28 2018-11-11T00:
source share

I think addSelf' should be of the form

 let inline addSelf' x = x + x 

But with the correct annotations like:

 let inline addSelf' (x : Wrap) = x + x 

Or something like that. I'm a little rusty on F # and can't check it right now.

0
Jul 27 '11 at 18:52
source share

If you remove inline from static (+) function ie

 type Wrap<'a> = | Wrap of 'a static member (+) (Wrap x, Wrap y) = Wrap (x + y) 

Than it works great.

I assume this is due to the fact that in addSelf' compiler is trying to find the + operator in the Wrap type, and since + was built in, it does not match the search criteria.

0
Jul 28 '11 at 5:12
source share



All Articles