F# - Overload Functions
Is there a way to do开发者_JS百科 somehow overload a function?
Let's take those 3 functions:
// Returns StringPropertyInfo
let stringProperty (expr:Expr<'a -> string>) (cfg:EntityInfo<'a>) =
cfg.Property expr
// Returns DatePropertyInfo
let dateProperty (expr:Expr<'a -> System.DateTime>) (cfg:EntityInfo<'a>) =
cfg.Property expr
// Returns BytePropertyInfo
let byteProperty (expr:Expr<'a -> System.Byte>) (cfg:EntityInfo<'a>) =
cfg.Property expr
is there a way to merge them all into just:
let property expr cfg = ....
if not, whats the most neat way to accomplish something similar?
If you want to use an approach based on discriminated unions, then I think the declaration is more suitable (as you don't need to manipulate with quotations). Slight modification of the type suggested by Alex is:
type PropertyInfo<'a> =
| String of Expr<'a -> string>
| Date of Expr<'a -> System.DateTime>
| ...
Then you'd write something like:
let property (pi:PropertyInfo<'a>) (cfg:EntityInfo<'a>) =
match pi with
| String e -> cfg.Property e
| ...
cfg |> property (String <@ fun e -> e.Foo @>)
Another option would be to implement property
as a static member of a type, in which case you can use usual overloading (similar to C#). Something like:
type EF =
static member property (expr:Expr<'a -> string>) (cfg:EntityInfo<'a>) =
cfg.Property expr
static member property (expr:Expr<'a -> System.DateTime>) (cfg:EntityInfo<'a>) =
cfg.Property expr
static member property (expr:Expr<'a -> System.Byte>) (cfg:EntityInfo<'a>) =
cfg.Property expr
Then you'd write:
cfg |> EF.property <@ e -> e.Foo @>
Finally, you could also make it a bit simpler (but less safer) by making the function fully generic and doing dynamic type test (to decide what return type is used). Something like:
let property<'a, 'r> (e:Expr<'a -> 'r>) (cfg:EntityInfo<'a>) =
if typeof<'r> = typeof<string> then
// ...
Short answer, no. There's another question dealing with this here.
You can however overload methods in classes etc. otherwise the .NET integration wouldn't work too well. This is one possible solution albeit not in my eyes, a pretty one.
You could put them in different sub-modules.
Perhaps you could make a generic function and decide the return type through one of the parameters. I'm too much of a newbie when it comes to the type inference to say for certain though.
i think a discriminated union is your friend in this instance, you would have something like
type PropertyInfo =
| StringPropertyInfo of string
| DatePropertyInfo of System.DateTime
| BytePropertyInfo of byte
and then would match on it and do appropriate action returning the union in one function...
One semi-ugly way to get what you're looking for would be to generalize it a bit and use:
let inline property expr cfg =
(^t : (member Property : Expr<'a -> 'b> -> 'c)(cfg, expr))
However, this can be applied to values of types other than EntityInfo<'a>
, as long as they have a Property
member with the right signature.
精彩评论