Is this question solvable through functional idiomatic approach, could generics or discriminated unions be the answer?
Is it possible to have polymorphism with passing different types to a function while the function is consuming some common fields.
Idea is to be able to call and reuse the function with different types and use the common attributes/fields.
type Car = {
Registration: string
Owner: string
Wheels: int
customAttribute1: string
customAttribute2: string
}
type Truck = {
Registration: string
Owner: string
Wheels: int
customField5: string
customField6: string
}
let SomeComplexMethod (v: Car) =
Console.WriteLine("Registration" + v.Registration + "Owner:" + v.Owner + "Wheels" + v.Wheels
// some complex functionality
Use
SomeComplexMethod(car)
SomeComplexMethod(truck)
Edit
Following the answer. Is it possible to specify the type of the incoming v since JSON serializer asks for the associated type. If Car was supplied as input, Car will be output, If truck as input truck will be output.
let inline someComplexFun v =
let owner = (^v: (member Owner: string)(v))
let registration = (^v: (member Registration: string)(v))
// process input
use response = request.GetResponse() :?> HttpWebResponse
use reader = new StreamReader(response.GetResponseStream())
use memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(reader.ReadToEnd()))
(new DataContractJsonSerializer(typeof<Car>)).ReadObject(memoryStream) :?> Car
if truck was the input v
(new DataContractJsonSerializer(typeof<Truck>)).ReadObject(memoryStream) :?> Truck
This looks like the classical use case for object inheritance, or perhaps an interface. The difference is that an interface provides only methods (including properties, as they are methods under the hood), while a base object (abstract or concrete) can also provide fields.
In your case an interface might be appropriate:
type IVehicle =
abstract Registration : string
abstract Owner : string
abstract Wheels : int
type Car (_r, _o, _w) =
member customAttribute1 : string
member customAttribute2 : string
interface IVehicle with
member Registration = _r
member Owner = _o
member Wheels = _w
type Truck (_r, _o, _w) =
member customField5 : string
member customField6 : string
interface IVehicle with
member Registration = _r
member Owner = _o
member Wheels = _w
let someComplexMethod (v : IVehicle) =
stdout.WriteLine "Registration: " + v.Registration +
"\nOwner: " + v.Owner +
"\nWheels: " + v.Wheels
EDIT: You can do it without OOP by using a discriminated union, and several record types:
type VehicleBase =
{ Registration : string
Owner : string
Wheels : int }
type CarAttributes =
{ customAttribute1 : string
customAttribute2 : string }
type TruckAttributes =
{ customField5 : string
customField6 : string }
type Vehicle =
| Car of VehicleBase * CarAttributes
| Truck of VehicleBase * TruckAttributes
let processVehicle v =
stdout.WriteLine ("Registration: " + v.Registration +
"\nOwner: " + v.Owner +
"\nWheels: " + v.Wheels)
let someComplexMethod = function
| Car (v, _) -> processVehicle v
| Truck (v, _) -> processVehicle v
What you want is usually called structural (or duck) typing. It can be done via interfaces and object expressions in F# (the accepted way) or via SRTPs. The link @CaringDev provided gives you a quick rundown, but obviously you can find many more examples. Please read this and this. For your specific example it will depend how much control you have over the original types.
It's easy to define another type that includes the fields that you might want. Then your function (I found it interesting btw, that you so much want to go for a functional solution but named it a method...) should just take ANY type that has the required fields/properties. Generics won't work for you in this case, as you need to constrain to a subset of types. But once you have such a function, which uses statically resolved type parameters (SRTPs) you're good to go:
type Car = {
Registration: string
Owner: string
Wheels: int
customAttribute1: string
customAttribute2: string
}
type Truck = {
Registration: string
Owner: string
Wheels: int
customField5: string
customField6: string
}
type Bike = {
Owner: string
Color: string
}
type Vehicle = {
Registration: string
Owner: string
}
let inline someComplexFun v =
let owner = (^v: (member Owner: string)(v))
let registration = (^v: (member Registration: string)(v))
{Registration = registration; Owner = owner}
let car = {Car.Registration = "xyz"; Owner = "xyz"; Wheels = 3; customAttribute1= "xyz"; customAttribute2 = "xyz"}
let truck = {Truck.Registration = "abc"; Owner = "abc"; Wheels = 12; customField5 = "abc"; customField6 = "abc"}
let bike = {Owner = "hell's angels"; Color = "black"}
someComplexFun car //val it : Vehicle = {Registration = "xyz";
//Owner = "xyz";}
someComplexFun truck //val it : Vehicle = {Registration = "abc";
//Owner = "abc";}
someComplexFun bike //error FS0001:
The Vehicle type is defined but it could be anything. Then someConplexFun is defined that can take any type, that has Owner and Registration. It has to be inline and its type signature is:
val inline someComplexFun :
v: ^v -> Vehicle
when ^v : (member get_Owner : ^v -> string) and
^v : (member get_Registration : ^v -> string)
You can pass any type that has Owner and Registration fields, and it will return a Vehicle but of course you can just print it out or return a tuple, etc. For the Bike type, since it doesn't have Registration this function will fail.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With