карринг «гибких типов» в F # - PullRequest
5 голосов
/ 17 марта 2012

Небольшая часть кода для выделения проблемы:

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!

Может кто-нибудь объяснить, почему поведение компилятора так сильно отличается в последних двух строках? И почему мы потеряли информацию (о гибкой #Stream) в функции test_currying?

1 Ответ

3 голосов
/ 19 марта 2012

Это похоже на ошибку для меня.Компилятор по-разному обрабатывает функции, созданные с использованием 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

В соответствии со спецификацией (раздел 14.4.2 , опубликованный Брайаном в удаленном (?) Ответе, гибкий тип, который позволяет использовать супертипы, должен быть вставлен независимо от того, является ли вызванная функция членом или значением с привязкой.

...