Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

currying of 'flexible types' in F#

Tags:

types

currying

f#

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?

like image 216
qehgt Avatar asked Oct 23 '22 05:10

qehgt


1 Answers

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.

like image 157
Tomas Petricek Avatar answered Oct 30 '22 14:10

Tomas Petricek