这个F#curried功能有什么问题?

时间:2015-02-18 15:45:33

标签: f# functional-programming

我正在写这个名为inner的curried f#函数,该函数应该将2个列表作为参数并根据位置相乘,然后返回总和:

let rec inner xs = 
    let aux ys = function
    | ([], ys) -> 0
    | (xs, []) -> 0
    | (x::xs, y::ys) -> (x*y) + inner xs ys
    aux ys;;
inner [1;2;3] [4;5;6];;

在这种情况下,答案是32,因为1 * 4 + 2 * 5 + 3 * 6 = 32.并且它有效,但是有这样的信息:

  

错误FS0001:类型不匹配。期待着       'a list -> 'd
  但是给了一个       'b list * 'a list -> int

     

类型'a list与类型'b list * 'a list

不匹配

老实说,在调用它以使其正常工作时,我不知道放在aux旁边的内容。

2 个答案:

答案 0 :(得分:2)

我不确定究竟是什么误解。我注意到三个奇怪的观点:

  • let aux ys = function ([], ys) ->声明并立即重新声明,从而隐藏标识符ys。请注意,aux是一个带有两个curried参数的函数,其中第二个是2元组。我怀疑这是你的意图。

  • aux函数以相当不寻常的方式缩进;通常,它应该得到另一个四个空格的缩进。编译器可能不会抱怨这一点,只是在模式匹配后退出范围,但它增加了对失败行应该做什么的困惑。

  • ys未定义上次使用的位置。 (这可能与令人困惑的缩进有关吗?)

以下是两种写作方式:

不是尾递归

let rec inner xs ys = 
    match xs, ys with
    | x::xt, y::yt -> x * y + inner xt yt
    | _ -> 0

在此版本中,curried参数转换为元组并用于匹配表达式。 (由于最后的添加,这可能会导致大型输入列表的堆栈溢出。)

尾递归,辅助功能

let rec private aux acc = function
    | x::xs, y::ys -> aux (acc + x * y) (xs, ys)
    | _ -> acc

let inner xs ys = aux 0 (xs, ys)

这里,辅助函数有两个curried参数,其中第一个是累加器,第二个是保存两个列表的元组。 inner成为一个包装器函数,它通过初始化零来剥离累加器 - 并将tupled参数转换为curried参数,这也是要求。 (由于递归调用的值是函数返回值,因此该函数支持尾递归编译。)

答案 1 :(得分:1)

定义后,您需要调用aux函数。目前,您的inner函数只是定义了它,并没有对它做任何事情。

在这种情况下,如果您将aux函数定义为采用两个参数,我不确定您是否确实需要定义inner

let rec inner (tuple : int list * int list) =
    match tuple with
    | ([], ys) -> 0
    | (xs, []) -> 0
    | (x :: xtail, y :: ytail) -> x * y + inner (xtail, ytail)

inner ([1;2;3], [4;5;6]) // 32

如果您想保留咖喱表格,则以下内容应该有效。您需要在匹配中包含xs,然后返回aux(将包含第一个列表并期望第二个列表):

let rec inner xs = 
    let aux ys =
        match xs, ys with
        | ([], ys) -> 0
        | (xs, []) -> 0
        | (x::xs, y::ys) -> (x*y) + inner xs ys
    aux

inner [1;2;3] [4;5;6];; // 32