如何在 FunScript 中传递 "Function" 类型?
How to pass a "Function" type in FunScript?
我遇到了需要传递给 JQueryAnimationOptions
对象的 Function
类型。我通常会将 lambda 传递给回调,但这些似乎 不兼容 。我在 FunScript 存储库中查找了所有可以找到的示例。并且找不到任何解决方法。
它还说 Function
在用作 return 语句 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)
没关系,我找到了解决方案,我必须 unbox
lambda:
options.complete <- unbox<Function> (fun _ -> sayHelloFrom("F#"))
在 F# 和 C# 之间传递 lambda 时,这或多或少会像您预期的那样工作。在 F# 中,可以柯里化函数,而在 C#(和 JavaScript)中则不能。因此,当您需要将 lambda 从 F# 发送到 C# 时,您需要先对其进行转换。在 F# 中,这是通过像这样包装 lambda 来完成的:
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# lambda 传递给需要 C# lambda 的方法时,编译器会自动为您进行包装。那么前面的例子就变成了:
let ar = [|1;2;3|]
let acc = ar.Aggregate( fun x y -> x + y )
(当然,在这种情况下,使用惯用的 Array.reduce 会更好。这只是一个人为的例子。)
这在使用 FunScript 与 JS 交互时完全相同。您唯一需要注意的是 F# lambda 如何转换为 JS。为了允许柯里化,带有两个或更多参数的 lambda 像 fun x y -> x + y
变成:
function (x) {
return function (y) {
return x + y;
}
}
这可能是个问题,因为原生 JS 需要以下签名:function (x, y)
。在这种情况下,您必须像与 C# 交互时一样用 System.Func<_,_,_>()
包装 lambda(请记住,如果您将 lambda 传递给方法,这是自动完成的)。
然而,只有一个参数的 lambda 没有任何问题:fun x -> x*x
变成 function (x) { return x*x; }
。在这种情况下,您不需要将它们包装起来(无论如何这样做都没有坏处)并且在必要时使用 unbox
来安抚 F# 编译器就足够了。请注意,FunScript 编译器会忽略最终 JS 代码中的 unbox
,因此在运行时根本不会进行类型检查。
希望解释清楚。如果不是,请添加评论,我会编辑答案。
我遇到了需要传递给 JQueryAnimationOptions
对象的 Function
类型。我通常会将 lambda 传递给回调,但这些似乎 不兼容 。我在 FunScript 存储库中查找了所有可以找到的示例。并且找不到任何解决方法。
它还说 Function
在用作 return 语句 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)
没关系,我找到了解决方案,我必须 unbox
lambda:
options.complete <- unbox<Function> (fun _ -> sayHelloFrom("F#"))
在 F# 和 C# 之间传递 lambda 时,这或多或少会像您预期的那样工作。在 F# 中,可以柯里化函数,而在 C#(和 JavaScript)中则不能。因此,当您需要将 lambda 从 F# 发送到 C# 时,您需要先对其进行转换。在 F# 中,这是通过像这样包装 lambda 来完成的:
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# lambda 传递给需要 C# lambda 的方法时,编译器会自动为您进行包装。那么前面的例子就变成了:
let ar = [|1;2;3|]
let acc = ar.Aggregate( fun x y -> x + y )
(当然,在这种情况下,使用惯用的 Array.reduce 会更好。这只是一个人为的例子。)
这在使用 FunScript 与 JS 交互时完全相同。您唯一需要注意的是 F# lambda 如何转换为 JS。为了允许柯里化,带有两个或更多参数的 lambda 像 fun x y -> x + y
变成:
function (x) {
return function (y) {
return x + y;
}
}
这可能是个问题,因为原生 JS 需要以下签名:function (x, y)
。在这种情况下,您必须像与 C# 交互时一样用 System.Func<_,_,_>()
包装 lambda(请记住,如果您将 lambda 传递给方法,这是自动完成的)。
然而,只有一个参数的 lambda 没有任何问题:fun x -> x*x
变成 function (x) { return x*x; }
。在这种情况下,您不需要将它们包装起来(无论如何这样做都没有坏处)并且在必要时使用 unbox
来安抚 F# 编译器就足够了。请注意,FunScript 编译器会忽略最终 JS 代码中的 unbox
,因此在运行时根本不会进行类型检查。
希望解释清楚。如果不是,请添加评论,我会编辑答案。