这个 F# 柯里化函数有什么问题?
What is wrong with this F# curried function?
我正在编写这个名为 inner
的柯里化 f# 函数,它应该将 2 个列表作为参数并根据位置将两者相乘,然后 return 总和:
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。它有效,但有这条消息:
error FS0001: Type mismatch. Expecting a
'a list -> 'd
but given a
'b list * 'a list -> int
The type 'a list
does not match the type 'b list * 'a list
老实说,我不知道在 aux
旁边放什么才能让它工作。
您需要在定义后调用您的 aux
函数。目前,您的 inner
函数只是定义它,不对其执行任何操作。
在这种情况下,如果您将 inner
函数定义为采用两个参数,我不确定您是否真的需要定义 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
,然后只包含 return 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
我不确定到底是什么误会。我注意到三个奇怪的点:
let aux ys = function ([], ys) ->
声明并立即重新声明,从而隐藏标识符 ys
。请注意,aux
是一个具有两个柯里化参数的函数,其中第二个是一个二元组。我怀疑这是你的意图。
aux
函数以一种非常不寻常的方式缩进;通常,它应该再缩进四个 space。编译器可能不会抱怨这一点,只是在模式匹配后退出范围,但它增加了对失败行应该做什么的混淆。
ys
在上次使用的地方未定义。 (这可能与令人困惑的缩进有关吗?)
这里有两种写法:
不是尾递归
let rec inner xs ys =
match xs, ys with
| x::xt, y::yt -> x * y + inner xt yt
| _ -> 0
在此版本中,柯里化参数被转换为元组并用于匹配表达式。 (由于最后添加,这可能会导致大型输入列表的堆栈溢出。)
尾递归,带辅助函数
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)
这里,辅助函数有两个柯里化参数,第一个是累加器,第二个是包含两个列表的元组。 inner
成为一个包装函数,它既剥离累加器——通过用零初始化它——并将元组参数转换为柯里化参数,这是要求。 (由于递归调用的值为函数return的值,所以该函数支持尾递归编译。)
我正在编写这个名为 inner
的柯里化 f# 函数,它应该将 2 个列表作为参数并根据位置将两者相乘,然后 return 总和:
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。它有效,但有这条消息:
error FS0001: Type mismatch. Expecting a
'a list -> 'd
but given a
'b list * 'a list -> int
The type
'a list
does not match the type'b list * 'a list
老实说,我不知道在 aux
旁边放什么才能让它工作。
您需要在定义后调用您的 aux
函数。目前,您的 inner
函数只是定义它,不对其执行任何操作。
在这种情况下,如果您将 inner
函数定义为采用两个参数,我不确定您是否真的需要定义 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
,然后只包含 return 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
我不确定到底是什么误会。我注意到三个奇怪的点:
let aux ys = function ([], ys) ->
声明并立即重新声明,从而隐藏标识符ys
。请注意,aux
是一个具有两个柯里化参数的函数,其中第二个是一个二元组。我怀疑这是你的意图。aux
函数以一种非常不寻常的方式缩进;通常,它应该再缩进四个 space。编译器可能不会抱怨这一点,只是在模式匹配后退出范围,但它增加了对失败行应该做什么的混淆。ys
在上次使用的地方未定义。 (这可能与令人困惑的缩进有关吗?)
这里有两种写法:
不是尾递归
let rec inner xs ys =
match xs, ys with
| x::xt, y::yt -> x * y + inner xt yt
| _ -> 0
在此版本中,柯里化参数被转换为元组并用于匹配表达式。 (由于最后添加,这可能会导致大型输入列表的堆栈溢出。)
尾递归,带辅助函数
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)
这里,辅助函数有两个柯里化参数,第一个是累加器,第二个是包含两个列表的元组。 inner
成为一个包装函数,它既剥离累加器——通过用零初始化它——并将元组参数转换为柯里化参数,这是要求。 (由于递归调用的值为函数return的值,所以该函数支持尾递归编译。)