这个F#curried函数有什么问题?

这个F#curried函数有什么问题?,f#,functional-programming,F#,Functional Programming,我正在编写一个名为internal的通用f#函数,该函数应将两个列表作为参数,并根据位置将两者相乘,然后返回总和: 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,因为

我正在编写一个名为
internal
的通用f#函数,该函数应将两个列表作为参数,并根据位置将两者相乘,然后返回总和:

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列表
与类型
'b列表*'a列表


老实说,我不知道在调用
aux
使其工作时,应该在它旁边放什么。

在定义了
aux
函数后,需要调用它。目前,您的
内部函数只定义了它,而不使用它

在这种情况下,如果将
内部
函数定义为接受两个参数,我不确定您是否真的需要定义
aux

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
(这将包含第一个列表,并且需要第二个列表):


定义后需要调用
aux
函数。目前,您的
内部函数只定义了它,而不使用它

在这种情况下,如果将
内部
函数定义为接受两个参数,我不确定您是否真的需要定义
aux

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
(这将包含第一个列表,并且需要第二个列表):


定义后需要调用
aux
函数。目前,您的
内部函数只定义了它,而不使用它

在这种情况下,如果将
内部
函数定义为接受两个参数,我不确定您是否真的需要定义
aux

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
(这将包含第一个列表,并且需要第二个列表):


定义后需要调用
aux
函数。目前,您的
内部函数只定义了它,而不使用它

在这种情况下,如果将
内部
函数定义为接受两个参数,我不确定您是否真的需要定义
aux

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
(这将包含第一个列表,并且需要第二个列表):


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

  • 让aux ys=function([],ys)->
    声明并立即重新声明标识符,从而隐藏标识符
    ys
    。请注意,
    aux
    是一个具有两个常用参数的函数,其中第二个参数是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参数,第一个是累加器,第二个是保存两个列表的元组
internal
变成了一个包装函数,它通过初始化累加器来剥离累加器,并将元组参数转换为curried参数,就像需求一样。(由于递归调用的值是函数的返回值,因此此函数支持尾部递归编译。)

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

  • 让aux ys=function([],ys)->
    声明并立即重新声明标识符,从而隐藏标识符
    ys
    。请注意,
    aux
    是一个具有两个常用参数的函数,其中第二个参数是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参数,第一个是累加器,第二个是保存两个列表的元组
internal
成为一个包装函数,它通过使用零初始化累加器来剥离累加器,并将元组参数转换为curry参数