【问题标题】:Recursive function to repeat string in OCaml在 OCaml 中重复字符串的递归函数
【发布时间】:2018-03-04 08:47:34
【问题描述】:

我是绝对的 OCaml 初学者。我想创建一个重复字符 20 次的函数。 就是这个功能,但是出错了,不能用。

let string20 s =
  let n = 20 in
  s ^ string20 s (n - 1);;

string20 "u";;

我想这样跑

# string20 "u"
- : string = "uuuuuuuuuuuuuuuuuuuu"

【问题讨论】:

  • 您应该首先考虑递归函数的停止条件。然后你应该知道在 ocaml 中用于声明递归函数的语法(这是 ocaml 课程级别)。
  • 你能输入你收到的错误吗?
  • 有点跑题了,但String.make 20 'u' 能胜任。
  • string20 接受单个参数 s,但在第二次及之后提供了 sn-1
  • 你把这个问题编辑得面目全非了,所以我把它回滚了,因为原来的问题有几个很好的答案。

标签: recursion ocaml


【解决方案1】:

您的函数 string20 采用一个参数,但您使用 2 个参数递归调用它。

基本的想法在那里,但不是完全正确的形式。一种方法是将 2 参数函数分离为单独的“辅助”函数。正如@PierreG 指出的那样,您需要将辅助函数作为递归函数来处理。

【讨论】:

    【解决方案2】:
    1. Ocaml 中的递归函数用let rec 定义
    2. 正如 cmets 中所指出的,您已将函数定义为采用一个参数,但您尝试使用两个参数进行递归调用。

    你可能想要这样的东西:

    let rec stringn s n =
      match n with
      1 -> s
    | _ -> s ^ stringn s (n - 1)
    ;;
    

    【讨论】:

    • 命名stringn 是非常多余的,因为Ocaml 函数是柯里化的,你可以做类似let stringN = string N in stringN "foo" 的事情
    【解决方案3】:
    let rec string n s =
      if n = 0 then "" else s ^ string (n - 1) s
    
    let string20 = string 20
    

    【讨论】:

      【解决方案4】:

      将函数分为“固定”部分和归纳部分是一种常见的模式。在这种情况下,需要一个嵌套的辅助函数来在新范围内执行真正的递归工作,而我们希望将输入字符串s 固定为常量,以便我们可以使用附加到s2s2 是一个累加器,随着时间的推移会建立一系列字符串,而 c 是一个电感器,在基本情况下倒数到 1。

      let repeat s n = 
        let rec helper s1 n1 = 
          if n1 = 0 then s1 else helper (s1 ^ s) (n1 - 1)
        in helper "" n
      

      非尾调用版本更简单,因为您根本不需要辅助函数:

      let rec repeat s n = 
        if n = 0 then "" else s ^ repeat s (n - 1)
      

      在旁注中,对于像 Ocaml 这样具有一流函数的函数式语言,一个非常有趣的事情是柯里化(或部分应用程序)。在这种情况下,您可以创建一个名为repeat 的函数,该函数接受两个参数n 类型为ints 类型为string 如上所述,并将其部分应用于ns 像这样:

      # (* top-level *)
      # let repeat_foo = repeat "foo";;
      # repeat_foo 5;;
      - : bytes = "foofoofoofoofoo"   (* top-level output *)
      

      如果n 参数被标记如下:

      let rec repeat ?(n = 0) s = 
            if n = 0 then "" else s ^ repeat s (n - 1)
      

      可以利用应用顺序,使功能更加灵活:

      # (* top-level *)
      # let repeat_10 = repeat ~n:10;;
      # repeat_10 "foo";;
      - : bytes = "foofoofoofoofoofoofoofoofoofoo" (* top-level output *)
      

      请参阅我的帖子 Currying Exercise in JavaScript(虽然它是用 JavaScript 编写的,但很容易理解)和这个 lambda calculus primer

      【讨论】:

      • 为了实际工作,你的尾递归 helper 应该在基本情况下更好地返回 s2 并使用 "" 而不是 s 调用。此外,s1 是多余的。您上一个示例中的标签 ~n 来自哪里?
      • @AndreasRossberg 是的,谢谢您的更正。为了更清晰,我还添加了带标签的参数版本。
      • 我相信对helper 的调用仍然是错误的。你需要用空字符串来调用它,否则你会落后一个。
      猜你喜欢
      • 2021-09-22
      • 2021-06-24
      • 2012-10-17
      • 1970-01-01
      • 2015-12-08
      • 2011-10-16
      • 2019-03-17
      • 2020-08-12
      • 1970-01-01
      相关资源
      最近更新 更多