我正在学习 OCaml,在函数式编程方面遇到了一些麻烦......
我需要创建一个函数,用于替换给定整数列表的字符,即字符串中该索引处的字符。例如,我输入 [1;4] 'u'“Hello”,它输出“Hullu”。
这就是我想出的:
let remplace_positions lst c str =
let rec acc lst c str n l_index ret =
match (n >= String.length str, List.nth lst l_index = n) with
| true, _ -> ret
| _, true -> acc lst c (n+1) (l_index+1) (ret ^ (String.make 1 c))
| _, _ -> acc lst c (n+1) (l_index+1) (ret ^ (String.make 1 (String.get str n)))
in
acc lst c str 0 0 ""
但如您所见,最后两个匹配案例存在错误。它们是字符串 -> 字符串类型,但我希望它们是字符串类型。
有人知道如何在递归调用函数时修复这个问题吗?
当我测试你的功能时,我得到:
参照
(n+1)
以下行:这是因为您已指出第三个参数
acc
应该是string
,但随后您传递了一个int
。我认为你传递了太多参数
acc
,这让跟踪它们变得很困难。如果它们没有改变,内部函数就没有必要将它们作为参数。内部函数将能够从外部作用域访问绑定,只要它们没有被遮蔽。我们还可以分解出将字符转换为字符串。
同样的错误,但是代码更容易阅读。
现在,让我们删除不必要的
str
参数传递:现在它编译成功了。让我们运行它。
到底哪里出了问题?
好吧,让我们来追溯一下:
您已将列表索引增加到尝试访问超出范围的列表的程度,从而导致异常。
说实话,你的基本方法不值得保留。
List.nth
即使成功使用也是低效的,因为它是 O(n) 操作,而不是 O(1)。您最终需要做的是迭代列表,并将每个索引处的字符替换为您指定的字符。列表上的模式匹配提供了完成列表迭代的最惯用方法。
但在 OCaml 中,字符串是不可变的,这会让事情变得很混乱。获取子字符串并将它们重新连接在一起确实占用了大量空间。如果它们是可变的,那就更容易了。
幸运的是,
Bytes
模块就是为此而设计的。我们可以将其转换为可变bytes
类型,对其进行修改,然后再转换回string
。但实际上,遍历列表并对每个元素应用操作已经由 处理了
List.iter
。