【发布时间】:2014-11-10 19:38:08
【问题描述】:
下面的函数tally 非常简单:它以字符串s 作为参数,将其拆分为非字母数字字符,并计算结果“单词”的数量,不区分大小写。
open Core.Std
let tally s =
let get m k =
match Map.find m k with
| None -> 0
| Some n -> n
in
let upd m k = Map.add m ~key:k ~data:(1 + get m k) in
let re = Str.regexp "[^a-zA-Z0-9]+" in
let ws = List.map (Str.split re s) ~f:String.lowercase in
List.fold_left ws ~init:String.Map.empty ~f:upd
我认为由于混乱,这个函数比它应该的更难阅读。我希望我能写一些更接近这个的东西(我沉迷于一些“幻想语法”):
(* NOT VALID SYNTAX -- DO NOT COPY !!! *)
open Core.Std
let tally s =
let get m k =
match find m k with
| None -> 0
| Some n -> n ,
upd m k = add m k (1 + get m k) ,
re = regexp "[^a-zA-Z0-9]+" ,
ws = map (split re s) lowercase
in fold_left ws empty upd
我在上面所做的更改主要分为三组:
- 摆脱重复的
let ... in,合并所有绑定(到,-分隔的序列中;这,AFAIK,不是有效的OCaml); - 消除了函数调用中的
~foo:-type 噪音; - 去掉了
Str.、List.等前缀。
我可以使用有效的 OCaml 语法实现类似的效果吗?
【问题讨论】:
-
fyi,
Map.change是更新地图条目的更自然选择:let update m k = String.Map.change m k (function None -> Some 1 | Some n -> Some (n+1)) -
@ivg:谢谢!顺便说一句,为什么
Some 1 | ... Some (n+1),而不仅仅是1 | ... (n+1)?我以前见过这样的函数(即返回 onlySome's),但我看不出它们的基本原理。 -
change key f是一个瑞士刀函数。它的语义如下:如果key不存在,则f用None调用,否则用Some v调用,其中v是绑定到key的值。如果函数f返回Some u,则key会反弹到u,如果返回None,则key将被移除(如果存在)。 -
@ivg:好的,知道了。谢谢!
标签: ocaml