问题
This code doesn't compile:
let f = fun x y -> x <<< y // bit shift
let g = fun x y -> x <<< y
[<EntryPoint>]
let main _ =
printfn "%d" <| f 1 10
printfn "%d" <| f 1L 10 // error
printfn "%d" <| g 1L 10
0
(7,21): error FS0001: This expression was expected to have type
int
but here has type
int64
- http://ideone.com/qktsOb
I guess the unifier fixed the type parameters associated with f
and g
upon seeing their first occurrences. What governs this process? I think this is very similar to "value restriction" but f
and g
are already eta-expanded! This is a hard problem.
- http://en.wikipedia.org/wiki/Value_restriction
I would surely imagine there's some black magic behind typing predefined operators with ad-hoc polymorphism over integral types, but that's just my speculation. Any information appreciated.
回答1:
Generic numeric programming is done using static member constraints, which can't be represented in the .NET type system. They exist only in F# and therefore must be marked inline
.
Your code could be written this way:
let inline f x y = x <<< y // bit shift
let inline g z y = z <<< y
[<EntryPoint>]
let main _ =
printfn "%d" <| f 1 10
printfn "%d" <| f 1L 10 // works too
printfn "%d" <| g 1L 10
0
More info on MSDN:
Inline Functions
Statically Resolved Type Parameters
回答2:
I think it is how F# performs automatic generalization of function parameters. On first appearance it infers that the function 'f' could have type ('a -> 'a -> 'a) but the second appearance is not match this signature because it has a different signature ('b -> 'a -> 'a) because it consider int64 and int as different types.
Inlining functions could sometimes solve this problem as @Daniel mentioned
Slightly more info could be found here: http://msdn.microsoft.com/en-us/library/dd233183.aspx
Some more info on static member constraints could be found in this post by Tomas Petricek: http://tomasp.net/blog/fsharp-generic-numeric.aspx/
来源:https://stackoverflow.com/questions/26632912/f-arithmetic-operator-and-loss-of-polymorphism-value-restriction