在F#中讨论'灵活类型'

qeh*_*hgt 5 f# types currying

代码的一小部分,以突出问题:

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!
Run Code Online (Sandbox Code Playgroud)

有人可以解释一下,为什么编译器的行为在最后两行中如此不同?为什么我们#Streamtest_currying功能上丢失了信息(关于灵活性)?

Tom*_*cek 3

这对我来说看起来像是一个错误。编译器处理使用不同构造的函数let和编写为static member.

特别是,我认为它不会为未在成员声明中显式声明的成员参数插入灵活类型(即,参数要么是部分函数应用程序的结果,要么是使用构造创建的参数fun)。

演示该行为的最简单示例不使用灵活类型,如下所示:

type A = 
  static member op = fun (s:obj) -> ()
module B =
  let op = fun (s:obj) -> ()

A.op "A" // Error 
B.op "A" // Ok
Run Code Online (Sandbox Code Playgroud)

根据规范(第14.4.2节,由 Brian 在删除的(?)答案中发布),无论调用的函数是成员还是 let 绑定值,都应该插入允许使用超类型的灵活类型。