在F#中是否可以进行递归局部函数应用?

时间:2019-02-11 07:48:40

标签: recursion f#

我正在使用函数2x ^ 2 + y ^ 2,在我的代码中定义为:

fx = fun x y -> (2 * (pown x 2)) + (pown y 2)

我想知道是否可以递归地应用x和y分量?

当前,如果我愿意

let f1 = fx 0.0 //<fun:it@9-2>
let f2 = f1 2.0 //4.0

然后按预期工作。但是,如果我要给函数ab参数指定间隔,则intellisense会适合。

let ab = [0.0; 2.0]

let result =
    let rec getres fn lst =
        match lst with
        | hd :: tl -> 
            let f1 = fn hd
            getres f1 tl   // <- error here
        | [] -> fn
    getres fx ab

然后f1上的intellisense给我一个错误:

Type mismatch. Expecting a 
  "a -> 'b' 
but given a 
  "b'. 
The types "a' and "b -> 'a' cannot be unified 

我希望能够将参数列表(例如,上例中的ab列表)中的任意数量的参数递归地应用到我提供给表达式的函数中,形式为{{ 1}}。这可能吗?

1 个答案:

答案 0 :(得分:3)

我认为您可能需要为getres的函数参数指定一个签名。根据错误消息,编译器推断fn接受单个参数并返回结果。因此在错误行f1上不是函数而是值。就是没有任何烦人的事情发生。

但是,这将无法处理您想要执行功能而不是执行部分应用程序的最终情况。您可能需要额外的间接级别来处理此问题。 (在其他.NET语言中,可能需要为此使用反射-允许调用一个函数来传递参数数组-在强类型.NET语言中,如果没有反射就无法处理它。)


其他(总结以下评论):

请考虑所需的getres签名。如果fn是两个参数的函数(即'a -> 'a -> 'b),则getres具有签名:

('a -> 'a -> 'b) -> list 'a -> ('a -> 'b`)

第一次通话。

但是,当getres的实例进行递归调用时,它需要是一个带有单个参数的函数,即。它的签名必须是:

('a -> 'b) -> list 'a -> 'b`

使用单个F#函数是不可能的。

.NET函数(即类成员)是可能的,但前提是必须分别编写每个“级别”(即,硬编码最大数量的参数)。 (比较.NET运行时中System.Func<T1, TRes>System.Func<T1, T2, TRes>的定义。)

(这是动态语言可以轻松处理的事情,但是强类型语言需要在其基础上使用非常复杂的类型系统来实现。)