Small part of a code to highlight the problem:
open System.IO
let do_smth i (stm : #System.IO.Stream) = // val do_smth : 'a -> #Stream -> unit
(*....*)
()
type SomeOps = SomeOps with
static member op (i : int) = do_smth i
let test_currying i = do_smth i // val test_currying : 'a -> (Stream -> unit)
// NB: Stream, not #Stream
let main() =
use stm = new System.IO.MemoryStream()
test_currying 42 stm // OK, upcasted to Stream somehow
SomeOps.op 42 stm // compiler error!
Can someone explain, why is compiler's behavior so different in last two lines? And why we lost information (about flexible #Stream
) in test_currying
function?
This looks like a bug to me. The compiler handles differently functions constructed using let
and functions written as static member
.
In particular, I think that it does not insert flexible types for member arguments that are not explicitly declared in the member declaration (that is, arguments that are either the result of partial function application or are created using the fun
construct).
The simplest example that demonstrates the behavior does not use flexible type and looks like this:
type A =
static member op = fun (s:obj) -> ()
module B =
let op = fun (s:obj) -> ()
A.op "A" // Error
B.op "A" // Ok
According to the specification (Section 14.4.2, posted by Brian in a deleted (?) answer), a flexible type that allows using supertypes should be inserted regardless of whether the invoked function is member or a let-bound value.
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