Как передать тип "Функция" в FunScript?
Я сталкиваюсь с этим Function
типа, что мне нужно передать JQueryAnimationOptions
объект. Обычно я передаю лямбду обратным вызовам, но они кажутся несовместимыми. Я посмотрел каждый образец, который мог найти в репозитории FunScript. и не мог найти обходной путь.
Он также сказал, что Function
на самом деле интерфейс (для чего?) при использовании в качестве оператора возврата Error: Invalid use of interface type
,
Так как передать аргумент обратного вызова с этим Function
тип?
код:
[<FunScript.JS>]
module Main
open FunScript
open FunScript.TypeScript
let sayHelloFrom (name:string) =
Globals.window.alert("Hello, " + name)
let jQuery (selector:string) = Globals.jQuery.Invoke selector
let main() =
let options = createEmpty<JQueryAnimationOptions>()
options.duration <- 3000
options.complete <- (fun _ -> sayHelloFrom("F#"))
let properties = createEmpty<Object>()
properties.Item("opacity") <- 1
let mainContent = jQuery "#mainContent"
mainContent.animate(properties, options) |> ignore
mainContent.click(fun e -> sayHelloFrom("F#") :> obj)
2 ответа
Это работает более или менее, как и следовало ожидать при передаче лямбда между F# и C#. В F# функции могут быть карри, а в C# (и JavaScript) - нет. Поэтому, когда вам нужно отправить лямбду из F# в C#, вам нужно сначала преобразовать ее. В F# это делается, оборачивая лямбду следующим образом:
open System.Linq
open System.Collections.Generic
let ar = [|1;2;3|]
let f = fun (x: int) (y: int) -> x + y
let acc = ar.Aggregate( System.Func<int,int,int>(f) )
На самом деле, компилятор F# может выводить типы в большинстве случаев, поэтому вам нужно только написать: System.Func<_,_,_>(f)
, Кроме того, при передаче лямбда-выражения F# методу, ожидающему лямбда-выражение C#, компилятор автоматически выполняет перенос. Тогда предыдущий пример становится:
let ar = [|1;2;3|]
let acc = ar.Aggregate( fun x y -> x + y )
(Конечно, в этом случае было бы лучше использовать идиоматический Array.reduce. Это просто надуманный пример.)
Это работает точно так же при взаимодействии с JS с использованием FunScript. Единственное, о чем вам нужно знать, это как F# лямбды переводятся в JS. Чтобы разрешить карри, лямбда с двумя или более параметрами, такими как fun x y -> x + y
будет выглядеть так:
function (x) {
return function (y) {
return x + y;
}
}
Что может быть проблемой, потому что нативный JS будет ожидать следующую подпись: function (x, y)
, В этом случае вам придется обернуть лямбду System.Func<_,_,_>()
как при взаимодействии с C# (помните, что это делается автоматически, если вы передаете лямбду в метод).
Однако лямбды с одним параметром не предполагают никаких проблем: fun x -> x*x
становится function (x) { return x*x; }
, В этом случае вам не нужно оборачивать их (это не мешает делать это в любом случае), и достаточно просто использовать unbox
чтобы успокоить F# компилятор, когда это необходимо. Просто помните, что компилятор FunScript игнорирует unbox
в конечном коде JS, так что не будет никакой проверки типов во время выполнения.
Я надеюсь, что объяснение понятно. Пожалуйста, добавьте комментарий, если это не так, и я отредактирую ответ.
Неважно, я нашел решение, мне пришлось unbox
лямбда:
options.complete <- unbox<Function> (fun _ -> sayHelloFrom("F#"))