Reputation: 9914
Why do I get an error when trying to call transform
on an string?
type Truck = Truck
type Car = Car
type Vehicle<'a> =
| TruckWrapper of Truck * 'a
| CarWrapper of Car * 'a
type Truck with
member this.transform (x) = TruckWrapper(this, x)
type Car with
member this.transform (x) = CarWrapper(this, x)
type System.String with
member this.transform (x) =
match x with
| "truck" -> TruckWrapper(Truck, this)
| _ -> CarWrapper(Car, this)
let inline transform value x = (^T : (member transform : 'a -> Vehicle<'b>) (value, x))
let a = transform Truck 1
let b = transform Car (1, 2)
let c = transform "truck" 0
this will yield the following error
let c = transform "truck" 0
------------------^^^^^^^
stdin(77,19): error FS0001: The type 'string' does not support the operator 'transform'
whereas
let d = "vehicle".transform("truck")
works pretty fine
Upvotes: 1
Views: 136
Reputation: 5741
I'm not quite sure if the alternative Gustavo alludes to would work with your original code, since the String extension method has a different signature from your other transform
methods, member transform : x:string -> Vehicle<System.String>
vs. member transform : x:'a -> Vehicle<'a
>` otherwise.
If they have all the same type, then it's something along the lines of:
type IntermediateVehicle = IntermediateVehicle with
static member ($) (IntermediateVehicle, x : Truck) =
fun value -> x.transform value
static member ($) (IntermediateVehicle, x : Car) =
fun value -> x.transform value
static member ($) (IntermediateVehicle, x : string) =
fun value -> x.transform value
let inline transform value x = (IntermediateVehicle $ value) x
let a = transform Truck 1
let b = transform Car (1, 2)
let c = transform "truck" 0
// val a : Vehicle<int> = TruckWrapper (Truck,1)
// val b : Vehicle<int * int> = CarWrapper (Car,(1, 2))
// val c : Vehicle<int> = TruckWrapper (Truck,0)
Upvotes: 2
Reputation: 11362
Unfortunately, extension members are not usable from member constraints. This could be implemented in the compiler, but I doubt it will be any time soon — as far as I can tell, member constraints are a low-priority feature for the F# team.
Edit: for your own types: what happens is that when you define a type extension in the same module as the type itself, then it is compiled into a normal method on your type. If you move the extension to another module, then it is truly compiled as an extension and you will see the same behavior as with System.String
.
Upvotes: 3