Как передать тип "Функция" в 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#"))
Другие вопросы по тегам