Сделать обернутую функцию F # SRTP универсальной - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть универсальная функция, использующая статически разрешенные параметры типа

let inline divide a b = a / b

с подписью ^a -> ^a -> ^a

Я могу создать функцию-оболочку

let log f = 
    let result = f()
    printfn "Result: %A" result
    result

Если я создам функцию, например

let loggedDivide a b = log (fun () -> divide a b)

его подпись float -> float -> float вместо ^a -> ^a -> ^a, что означает

loggedDivide 2.0 5.0
loggedDivide 2 5 //error

Как это можно сделать?

Обратите внимание, что что-то подобное пропускает смысл повторного использования функций

let logValue a = printfn "Result: %A" a
divide 2.0 5.0 |> logValue
divide 2 5 |> logValue

И в этом случае вещи не остаются общими

let logValueAndReturn a = 
    printfn "Result: %A" a
    a

let divideAndLog a b = divide a b |> logValue
divideAndLog 2.0 5.0
divideAndLog 2 5 //error

1 Ответ

0 голосов
/ 04 сентября 2018

Вы также должны сделать свою производную функцию встроенной:

let inline loggedDivide a b = log (fun () -> divide a b)

Это позволит распространять ограничения:

val inline loggedDivide :
  a: ^a -> b: ^b ->  ^c
    when ( ^a or  ^b) : (static member ( / ) :  ^a *  ^b ->  ^c)

Причина этого заключается в том, что SRTP - это функция компилятора F #, которая разрешается во время компиляции, поэтому функции становятся специализированными путем встраивания в сайт вызова.

Если вы хотите, чтобы ваша функция оставалась обобщенной, она должна быть встроенной.

Обратите внимание, что причина, по которой ваша функция выводится как работающая с int, заключается в том, что это значение по умолчанию для \ и других математических операторов. В противном случае вы получите ошибку, указывающую на неоднозначность.

...