Возможно ли применение рекурсивной частичной функции в F #? - PullRequest
0 голосов
/ 11 февраля 2019

Я работаю с функцией 2x ^ 2 + y ^ 2, определенной в моем коде как:

fx = fun x y -> (2 * (pown x 2)) + (pown y 2)

, и мне было интересно, можно ли применить xи y компоненты рекурсивно?

В настоящее время, если я скажу, скажем,

let f1 = fx 0.0 //<fun:it@9-2>
let f2 = f1 2.0 //4.0

, то это работает, как и ожидалось.Однако, если бы я дал своим функциям a и b параметры для указания некоторого интервала, intellisense выбрасывает аппроксимацию.

let ab = [0.0; 2.0]

let result =
    let rec getres fn lst =
        match lst with
        | hd :: tl -> 
            let f1 = fn hd
            getres f1 tl   // <- error here
        | [] -> fn
    getres fx ab

, тогда intellisense на f1 выдает мне ошибку:

Type mismatch. Expecting a 
  "a -> 'b' 
but given a 
  "b'. 
The types "a' and "b -> 'a' cannot be unified 

Я хочу иметь возможность рекурсивно применять любое количество параметров из списка параметров (например, мой список ab в приведенном выше примере) к функции, которую я предоставляю своему выражению в форме fun x1 x2 x3 … xn -> x1 + x2 + x3 + … + xn.Это возможно?

1 Ответ

0 голосов
/ 11 февраля 2019

Я думаю, что вам может потребоваться указать сигнатуру для аргумента функции getres.На основании сообщения об ошибке компилятор делает вывод, что fn принимает один аргумент и возвращает результат.Таким образом, в строке ошибки f1 это не функция, а значение.То есть.карринг не происходит.

Но это не относится к последнему случаю, когда вы хотите выполнить функцию, а не выполнять частичное применение.Вам может понадобиться дополнительный уровень косвенности, чтобы справиться с этим.(В других языках .NET для этого нужно было бы использовать отражение - что позволяет вызывать функцию с передачей массива параметров - это может быть невозможно в строго типизированном языке .NET, чтобы справиться с этим без отражения.)


Дополнительно (для обобщения комментариев ниже):

Рассмотрим обязательную подпись getres.Если fn является функцией двух аргументов (т.е. 'a -> 'a -> 'b), тогда getres имеет подпись:

('a -> 'a -> 'b) -> list 'a -> ('a -> 'b`)

для первого вызова.

Но когда этот экземплярgetres делает свой рекурсивный вызов, он должен быть функцией, принимающей один аргумент, т.е.его подпись должна быть:

('a -> 'b) -> list 'a -> 'b`

Это невозможно с одной функцией F #.

Это возможно с функцией .NET (т. Е. Членом класса), но только если каждый «уровень» написан отдельно (т. Е. Жесткое кодирование максимального количества аргументов).(Сравните, как System.Func<T1, TRes>, System.Func<T1, T2, TRes> определены во время выполнения .NET.)

(Это то, с чем динамические языки могут легко справиться, но для языков со строгой типизацией нужна очень сложная система типов, лежащая в основеэто добиться.)

...