Почему функция с byref не может быть преобразована напрямую в делегат?

В обычных условиях функции F # могут быть преобразованы в делегаты путем вызоваnew DelegateType и передача функции в качестве аргумента. Но когда делегат содержитbyref Параметр, это невозможно напрямую. Например код:

type ActionByRef<'a> = delegate of 'a byref -> unit

let f (x:double byref) = 
    x <- 6.0

let x = ref 42.0
let d = new ActionByRef<_>(f)

не скомпилируется, выдав следующую ошибку:

Это значение функции используется для создания типа делегата, чья подпись включает аргумент byref. Вы должны использовать явное лямбда-выражение, принимающее 1 аргумент.

После ошибки измените код для использования

let d = new ActionByRef<_>(fun x -> f(&x))

работает. Но мой вопрос: зачем это нужно? Почему F # не разрешает преобразование из именованной функции в этот делегат, но преобразование из лямбды в порядке?

Я столкнулся с этим поведением при исследованииДругой вопрос, я понимаюbyref предназначен только для совместимости с другими языками .Net.

Ответы на вопрос(1)

Решение Вопроса

byref<'T> не является фактическим типом в F # - он выглядит как тип (чтобы упростить язык), но он компилируется в параметр, помеченныйout флаг. Это значит, чтоbyref<'T> может использоваться только там, где компилятор может использоватьout флаг.

Проблема со значениями функции заключается в том, что вы можете построить функцию, например, при частичном применении:

let foo (n:int) (b:byref<int>) = 
  b <- n

Когда вы проходитеfoo в качестве аргумента конструктора делегата это частный случай частичного применения (без аргументов), но частичное приложение фактически должно создать новый метод, а затем передать его делегату:

type IntRefAction = delegate of byref<int> -> unit  

let ac = IntRefAction(foo 5)

Компилятор может быть умным и генерировать новый метод сbyref параметр (илиout флаг), а затем передать его по ссылке на фактическую функцию, но, как правило, будет другой метод, сгенерированный компилятором, когда вы не используетеfun ... -> ... синтаксис. Обработка этого добавила бы сложности, и я думаю, что это относительно редкий случай, поэтому компилятор F # не делает этого и просит вас быть более явным ...

 ildjarn31 янв. 2012 г., 21:23
Да, C #out на самом делеref плюсSystem.Runtime.InteropServices.Out приписывать.
 Tomas Petricek31 янв. 2012 г., 14:00
@svick - Вы правы - на самом деле, на уровне IL, флагref и C #out не существует вообще ...
 svick31 янв. 2012 г., 12:45
Интересно, я не думал об этом. Я думаю, что один придурокbyref больше похожеrefнеout.

Ваш ответ на вопрос