我是Ocaml的新手,我正在尝试编写一个递归函数。
该函数获取对列表并返回一对列表,例如
[(1, 4); (2, 3); (5, 9); (6, 10)]) -> ([1; 2; 5; 6], [4; 3; 9; 10])
但是编译器说:Error: This expression has type 'a list * 'b list
but an expression was expected of type 'a list
在第(unzip (List.tl m))
行
有人可以解释为什么我有这个错误吗?无论如何要解决这个问题吗?非常感谢你!
let rec unzip m =
if List.length m = 0 then
([], [])
else
((fst (List.hd m)) :: (unzip (List.tl m)), (snd (List.hd m)) :: (unzip (List.tl m)))
in
unzip m;;
答案 0 :(得分:3)
对于任何递归,您必须注意输出类型将始终相同。
让我们看看您的unzip
功能。
[(1, 4); (2, 3); (5, 9); (6, 10)]) -> ([1; 2; 5; 6], [4; 3; 9; 10])
简单地说,unzip
的返回类型是def 一对(元组),每个元素都是一个列表,对吗?
然后让我们看看你的代码
let rec unzip m =
if List.length m = 0 then
([], [])
else
((fst (List.hd m)) :: (unzip (List.tl m)), (snd (List.hd m)) :: (unzip (List.tl m)))
in
unzip m;;
你有两个分支。第一个分支返回([], [])
。好的,就返回类型而言,它是正确的,因为它是一对有两个空列表并匹配上述返回类型。
第二个分支
((fst (List.hd m)) :: (unzip (List.tl m)), (snd (List.hd m)) :: (unzip (List.tl m)))
是正确的吗?
这是一对有两个元素,没问题,然后让我们看第一个元素:
(fst (List.hd m)) :: (unzip (List.tl m))
您正尝试将(fst (List.hd m))
添加到(unzip (List.tl m))
的头部。
但是你只能使用::
向列表添加内容,所以ocaml假设(unzip (List.tl m))
是一个列表,对吗?
但它是一个unzip
函数应用程序,显然在开头描述,你的unzip
没有返回一个列表,而是一对(元组)。
所以ocaml不明白并因此抱怨。
以上只是回答您关于类型问题的问题。但是你的代码有更多问题。
<强> 1。错误使用in
假设您有一个函数f1
。您可以将其成像为母功能,这意味着它可以直接使用。同样在f1
中,您可以声明另一个函数或变量(或者更正式地说,绑定)。只有在函数内声明绑定时,才使用let...in...
。如果您只有母函数,则不要使用in
,因为in where
?
在unzip
中,您只有一个unzip
本身的功能或绑定,它位于顶层。所以in
不是必需的。
<强> 2。不正确的递归逻辑
我不知道如何向你解释这里的递归,因为它需要你阅读更多并练习更多。
但你想法中的正确代码是
let rec unzip = function
| [] -> ([], [])
| (x,y)::tl ->
let l1, l2 = unzip tl in
x::l1, y::l2
如果你追求的是更好的或尾部递归的版本,那么它是:
let unzip l =
let rec unzip_aux (l1,l2) = function
| [] -> List.rev l1, List.rev l2
| (x,y)::tl -> unzip_aux (x::l1, y::l2) tl
in
unzip_aux ([],[]) l
答案 1 :(得分:1)
错误来自于(unzip ...)
返回一对列表('a list * 'b list
)这一事实,您在编写(fst ..) :: (unzip ...)
时尝试将其作为列表进行操作。
如果您使用模式匹配,这一切都会写得更好。骨架:
let rec unzip = function
| [] -> ...
| (x,y) :: rest ->
let (xs, ys) = unzip rest in ...