F#中的动态函数

时间:2017-09-24 20:47:13

标签: f#

我试图探索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#中完成的概念,还是我缺少一种方法?

2 个答案:

答案 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]