Почему функция с 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# не делает этого и просит вас быть более явным...

Другие вопросы по тегам