F#和类似lisp的应用函数

时间:2014-02-14 12:16:16

标签: f# functional-programming

对于初学者来说,我是函数式编程和F#的新手,因此我不知道是否可以做这样的事情。所以我们假设我们有这个功能:

let sum x y z = x + y + z

由于某种原因,我们希望使用列表中的元素作为参数来调用它。我的第一次尝试只是这样做:

//Seq.fold (fun f arg -> f arg) sum [1;2;3] 

let rec apply f args =
    match args with
    | h::hs -> apply (f h) hs
    | [] -> f

...不编译。使用静态类型系统确定f的类型似乎是不可能的。
对于Haskell有identical question,唯一的解决方案是使用Data.Dynamic来输出类型系统。我认为在F#中最接近它的是Dynamitey,但我不确定它是否合适。这段代码

let dynsum = Dynamitey.Dynamic.Curry(sum, System.Nullable<int>(3))

生成类型为dynsum的{​​{1}}变量,并且无法调用此类型的对象,此外obj不是.NET代理。

所以问题是,如何在F#中使用/不使用该库来完成?

1 个答案:

答案 0 :(得分:3)

F#是一种静态类型的函数式语言,因此与F#一起使用的编程模式与您在LISP中使用的编程模式完全不同(实际上,它们也与您在Haskell中使用的编程模式不同)。因此,以您建议的方式使用函数不是您在正常的F#编程中所做的事情。

如果您对此功能考虑过一些情况,那么也许可以尝试询问原始问题,有人会帮您找到惯用的F#方法!

尽管如此,即使不推荐这样做,您也可以使用强大的.NET反射功能实现apply功能。这很慢且不安全,但如果偶尔有用的话。

open Microsoft.FSharp.Reflection

let rec apply (f:obj) (args:obj list) =
  let invokeFunc = 
    f.GetType().GetMethods()
    |> Seq.find (fun m -> 
        m.Name = "Invoke" && 
        m.GetParameters().Length = args.Length)
  invokeFunc.Invoke(f, Array.ofSeq args)  

代码查看函数的运行时类型,找到Invoke方法并调用它。

let sum x y z = x + y + z
let res = apply sum [1;2;3]
let resNum = int res

最后,您需要将结果转换为int,因为这不是静态的。