我试图探索F#的动态功能,以便我无法用静态类型系统表达某些功能。因此,我尝试为(例如)mapN
类型创建Option
函数,但我在创建具有动态数量参数的函数时遇到问题。我试过了:
let mapN<'output> (f : obj) args =
let rec mapN' (state:obj) (args' : (obj option) list) =
match args' with
| Some x :: xs -> mapN' ((state :?> obj -> obj) x) xs
| None _ :: _ -> None
| [] -> state :?> 'output option
mapN' f args
let toObjOption (x : #obj option) =
Option.map (fun x -> x :> obj) x
let a = Some 5
let b = Some "hi"
let c = Some true
let ans = mapN<string> (fun x y z -> sprintf "%i %s %A" x y z) [a |> toObjOption; b |> toObjOption; c |> toObjOption]
(它接受传入的函数并一次应用一个参数)编译,但是在运行时我得到以下内容:
System.InvalidCastException: Unable to cast object of type 'ans@47' to type
'Microsoft.FSharp.Core.FSharpFunc`2[System.Object,System.Object]'.
我意识到,为选项创建计算表达式,或者通过map2
左右定义map5
会更加惯用,但我特别想要探索F#的动态功能来查看是否有可能这样的事情。
这只是一个无法在F#中完成的概念,还是我缺少一种方法?
答案 0 :(得分:4)
我认为你只能用反思来采取这种方法。
但是,还有其他方法可以解决整体问题,而无需动态或使用您提到的其他静态选项。使用 ObjectBinding<ObservableList> ob = Bindings.createObjectBinding(() -> {
System.err.println("Binding here");
return null;
}, p);
ob.addListener((o) -> {
System.out.println("random action");
});
可以获得很多相同的便利,您需要自己定义(或从库中获取)。此代码被盗并改编自F# for fun and profit:
Option.apply
答案 1 :(得分:2)
要解释为什么您的方法不起作用,问题是您无法将parallel_coordinates(closing_data, 'Type', alpha=0.2, colormap=dark2_cmap)
plt.show()
类型的函数(表示为int -> int
)强制转换为类型FSharpFunc<int, int>
的值(表示为obj -> obj
)。类型是相同的泛型类型,但是转换失败,因为通用参数不同。
如果你插入了大量的装箱和拆箱,那么你的功能确实有效,但这可能不是你想写的东西:
FSharpFunc<obj, obj>
如果你想通过动态黑客探索更多选项 - 那么你可以使用F#反射做更多的事情。我通常不会在生产中使用它(简单更好 - 我只是手动定义多个地图功能或类似的东西),但以下运行:
let ans = mapN<string> (fun (x:obj) -> box (fun (y:obj) -> box (fun (z:obj) ->
box (Some(sprintf "%i %s %A" (unbox x) (unbox y) (unbox z))))))
[a |> toObjOption; b |> toObjOption; c |> toObjOption]