OCaml通过迭代列表更新值
我想知道如何通过迭代列表来更新变量的值。例如,假设我想跟踪列表的变量数量。我可以做类似OCaml通过迭代列表更新值
let list = [1;2;3;4;5]
let length = 0 in
let getCount elmt =
length = length+1 in
List.iter getCount list
,但我得到因为length = length+1
我比较使用=
我这是有道理的错误This expression has type 'a -> bool
。我应该如何更新长度值?
编辑:
我试图
let wordMap =
let getCount word =
StringMap.add word (1000) wordMap in
List.fold_left getCount StringMap.empty wordlist;;
,但它不知道什么wordMap是getCount将功能...
@PatJ给出了一个很好的讨论。但在真实的代码中,您只需使用折叠。折叠的目的正是你所要求的,在遍历列表时保持某种状态(任何你喜欢的类型)。
学会用褶皱思考是功能编程的基本技能,所以值得学习。
一旦你擅长折叠,你可以根据具体情况决定是否需要可变状态。在几乎所有情况下,你都不会。
为什么are'nt使用`List.length list`让你列表的长度(你绝对可以使用折叠积累的地图,同时遍历列表。)
如果目标是让列表的长度,只需使用List Module提供的功能:List.length
。否则,OCaml中的变量永远不会变化,你要做的事情在OCaml中是非法的,并且根本不起作用。但是,如果您确实需要更新价值,请考虑使用ref
(更多信息:http://www.cs.cornell.edu/courses/cs3110/2011sp/recitations/rec10.htm)。
你有几种方法来做到这一点。
更简单的方法(通常来自命令式世界的初学者首选)是使用参考。参考是一个可以合法变异的变量。
let length l =
let count = ref 0 in
let getCount _ = (* _ means we ignore the argument *)
count := !count + 1
in
List.iter getCount l;
!count
正如你可以看到这里,!count
在参考目前返回值和:=
允许你做了必要的更新。
但你不应该编写代码
是啊,我用大胆的,我这是怎么认真的。基本上,当你可以依靠纯函数编程时,你应该避免使用引用。也就是说,当没有副作用时。
那么,如果你不允许你如何修改变量?这就是递归进来检查这一点:
let rec length l =
match l with
| [] -> 0
| _::tl -> 1 + length tl
在该代码中,我们不再有一个count
变量。别担心,我们很快就会收回。但是您可以通过再次调用长度来看到,我们可以为参数l
分配一个新值tl
。但它是纯粹的,被认为是更好的做法。
好吧,差不多。
最后一个代码存在递归问题:每次调用都会向堆栈中添加(无用的)数据,并在通过列表之后进行添加。我们不希望这样。
但是,函数调用可以优化,如果他们是尾调用。作为Wikipedia可以解释给你听:
尾调用是作为 程序的最后执行的操作的子程序调用。
在后来的代码,length
递归调用不是尾呼叫作为+
是该函数的最后行动。通常的技巧是使用累加器来存储中间结果。我们称之为count
。
let rec length_iterator count l =
match l with
| [] -> count
| _::tl -> length_iterator (count+1) tl
in
let length l = length_iterator 0 l
现在我们有一个整洁,纯粹且易于优化的代码来计算列表的长度。
因此,要回答标题中所述的问题:使用(尾部)递归函数进行迭代,并将可更新变量作为此函数的参数。
谢谢帕特我实际上有你一样的优化尾部递归,但我问这个问题,因为我还有其他的东西我正在尝试做,所以我试图通过一个更简单的例子来学习这个概念。对于我的实际功能,而不是长度,我有一个地图用于存储元素的出现,这意味着我必须做Map.empty来得到一个空的地图,然后我必须通过添加地图来更新地图。我不知道该怎么做。 – jstnchng
@jstnchng,我不确定我理解你的问题。然后像@Jeffrey Scofield所说的那样,“fold”是你的朋友(基本上,它遍历并且你只是写出参数更新)。如果没有,请用代码示例更新你的问题,这样我们就可以看到你的精确的问题。 – PatJ
我想b你和杰弗里提到过,我应该先尝试折叠。感谢您的帮助,我会更新结果! – jstnchng
? – cago
这只是一个例子。对于我的实际功能,而不是长度,我有一个地图,我用来存储元素的出现次数,这意味着我必须做Map.empty才能得到一个空的地图,然后我必须通过添加来更新地图它。我不知道该怎么做。 – jstnchng
在OCaml中,如果你可以:一般你应该避免突变:不要使用可变的'ref'计数器,而是使用'List.fold_left'或'fold_right'来解决这类问题。 – camlspotter