代码之家  ›  专栏  ›  技术社区  ›  REALFREE

OCAML递归模式匹配

  •  7
  • REALFREE  · 技术社区  · 15 年前

    我正在尝试编写一个简单的递归函数,它检查列表并返回一对整数。这是很容易写在C/C++/Java,但我是新的OcAML,所以很难找出解决方案,由于类型冲突

    应该是……

    let rec test p l = ... ;;
    val separate : (’a -> bool) -> ’a list -> int * int = <fun>
    test (fun x -> x mod 2 = 0) [-3; 5; 2; -6];; 
    - : int * int = (2, 2)
    

    所以问题是如何递归地返回元组的值。

    2 回复  |  直到 6 年前
        1
  •  4
  •   goggin13    15 年前

    离开OCAML一段时间了,但我认为这将对realfree在评论中的描述起到关键作用。

    let rec test l = 
      match l with 
          [] -> (0,0) 
        | x::xs -> 
            if x > 0 then match (test xs) with (x,y) -> (x+1, y)
            else  match (test xs) with (x,y) -> (x, y+1);;
    

    可以使用嵌套的match语句提取要修改的元组片段

    编辑: 我不知道PascalCuoq在下面的评论中提到的语法,这是这样的代码,它更整洁,更简短:

    let rec test l = 
      match l with 
          [] -> (0,0) 
        | x::xs -> 
        if x > 0 then let (x,y) = test xs in (x+1, y)
        else let (x,y) = test xs in (x, y+1);;
    

    但公认的答案仍然更好,尤其是对于尾部递归;)。

        2
  •  5
  •   danben    15 年前

    这里的一个问题是,您返回两种不同的类型:空列表的int,否则返回元组。它必须是其中之一。

    另一个问题是您试图将1添加到 test 但是 测试 是函数,而不是值。您需要对其他东西调用test,以便它返回一个值,但即使这样,它也应该返回一个元组,您不能将其添加到整数中。

    我不知道你想让代码做什么,但是如果你用这个信息更新你的问题,我可以帮助更多。

    我有一个猜测是,你想计算列表中的正数,在这种情况下,你可以这样写:

    let rec test l = 
        match l with [] -> 0
       | x::xs -> if x > 0 then 1 + (test xs)
                  else test xs;;
    

    更新 :由于您已编辑以澄清问题,请按以下方式修改上述代码:

    let test l =
      let rec test_helper l pos nonpos = 
        match l with [] -> (pos, nonpos)
       | x::xs -> if x > 0 then test_helper xs 1+pos, nonpos
                  else test_helper xs pos 1+nonpos
      in test_helper l 0 0;;
    

    在这种情况下,使用蓄能器有很大帮助。它还使函数尾递归,这一直是很好的实践。