简体   繁体   English

Ocaml中的递归

[英]Recursion in Ocaml

I'm new to Ocaml and i'm trying to write a recursion function. 我是Ocaml的新手,我正在尝试编写一个递归函数。

The function take a list of pairs and return a pair of lists, for example 该函数获取一对列表并返回一对列表,例如

[(1, 4); (2, 3); (5, 9); (6, 10)]) -> ([1; 2; 5; 6], [4; 3; 9; 10])

But the compiler say that: Error: This expression has type 'a list * 'b list but an expression was expected of type 'a list 但是编译器说: Error: This expression has type 'a list * 'b list but an expression was expected of type 'a list

in the line (unzip (List.tl m)) 在行中(unzip (List.tl m))

Can someone explain why I have this error please? 有人可以解释为什么我有这个错误吗? And is there anyway to fix this? 而且有解决此问题的方法吗? Thank you very much! 非常感谢你!

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;; 

For any recursion, you have to note that the output type will be always the same. 对于任何递归,您都必须注意输出类型将始终相同。

Let's see your unzip function. 让我们看看您的unzip功能。

[(1, 4); (2, 3); (5, 9); (6, 10)]) -> ([1; 2; 5; 6], [4; 3; 9; 10])

Simply say, the return type of unzip is def a pair (tuple) , and each element is a list, correct? 简而言之, unzip的返回类型是def 对(元组) ,每个元素都是一个列表,对吗?


Then let's see your code 那我们来看一下你的代码

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;;

You have two branches. 您有两个分支。 First branch is returning ([], []) . 第一个分支正在返回([], []) Ok, in terms of return type, it is correct as it is a pair with two empty lists and matches the return type described above. 好吧,就返回类型而言,它是正确的,因为它是一对带有两个空列表并且匹配上述返回类型。


The second branch 第二支

((fst (List.hd m)) :: (unzip (List.tl m)), (snd (List.hd m)) :: (unzip (List.tl m)))

is it correct? 这是正确的吗?

It is a pair with two elements, no problem, then let's see the first element: 是一对有两个元素的对,没问题,接下来让我们看一下第一个元素:

(fst (List.hd m)) :: (unzip (List.tl m))

You are trying to add (fst (List.hd m)) to the head of (unzip (List.tl m)) . 您试图将(fst (List.hd m))(unzip (List.tl m))的头部。

But you can only add something to a list by using :: , so ocaml supposes (unzip (List.tl m)) is a list, right? 但是您只能使用::将某些东西添加到列表中,因此ocaml假定(unzip (List.tl m))是列表,对吗?

But it is a unzip function application, apparently described in the beginning, your unzip is not returning a list, but a pair (tuple). 但这是一个unzip功能的应用程序,显然是在一开始就描述的,您的unzip不是返回列表,而是一对(元组)。

So ocaml doesn't understand and thus complain. 因此,ocaml无法理解,因此会抱怨。


The above is just to answer your question about the type problem. 以上只是为了回答有关类型问题的问题。 But your code has more problems. 但是您的代码有更多问题。

1. incorrect use of in 1.不正确使用的in

Suppose you have a function f1 . 假设您有一个函数f1 You can image it as the mother function, which means it can be used directly. 您可以将其成像为母函数,这意味着它可以直接使用。 Also in f1 , you can declare another function or variable (or more formally, a binding). 同样在f1 ,您可以声明另一个函数或变量(或更正式地说,是绑定)。 Only when you declare a binding inside a function, you use let...in... . 仅当在函数内部声明绑定时,才使用let...in... If you only have the mother function, you don't use in , because in where ? 如果仅具有母亲功能,则不要in使用,因为in where

In your unzip , you only have one function or binding which is unzip itself and it is in top level. 在您的unzip ,您只有一个功能或绑定本身就是unzip ,并且位于顶层。 So in is not necessary. 所以in没有必要。

2. incorrect logic of recursion 2.递归逻辑不正确

I don't know how to explain to you about recursion here, as it needs you to read more and practise more. 我不知道如何在这里向您解释递归,因为它需要您阅读更多和练习更多。

But the correct code in your idea is 但是您想法中正确的代码是

let rec unzip = function
  | [] -> ([], [])
  | (x,y)::tl -> 
    let l1, l2 = unzip tl in
    x::l1, y::l2

If you are chasing for better or a tail-recursive version, here it is: 如果您追求的是更好的版本或尾部递归版本,则为:

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

The error comes from the fact that (unzip ...) returns a pair of lists ( 'a list * 'b list ), which you try to manipulate as a list when you write (fst ..) :: (unzip ...) . 错误来自以下事实: (unzip ...)返回一对列表( 'a list * 'b list ),您在编写(fst ..) :: (unzip ...)

This would all be written much more nicely if you used pattern-matching. 如果您使用模式匹配,那么所有这些都将写得更好。 Skeleton: 骨架:

let rec unzip = function
  | [] -> ...
  | (x,y) :: rest ->
    let (xs, ys) = unzip rest in ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM