F#的一点糖

重口味警告:本篇适合于追求代码直观到偏执狂地步,和宁愿绞尽脑汁减少几次击键的程序员,不喜勿入!

在Ruby里我们可以写出这样的代码:

hash.if_has_key k do |val|
#do sth. with val
end
 

这段代码描述性太强了,以至不需要解释就能让人明白。而且对比普通写法:

if hash.has_key k then
 val = hash[k]
 ...

end

< p>省了不少打字的功夫。为了在F#里也有这样的效果,我想了两种方法。首先,可以模拟Ruby。实现if_has_key的关键一是开放 class--事前要将if_has_key方法加入hash的类,二是block。F#和C# 3.0一样支持extension methods,而lambda expression可以代替block(虽然不完美),因此可以这样:

#light

type System.Collections.Generic.IDictionary with
    member this.if_has_key k f =
        if this.ContainsKey k then
            f this.[k]
        else
            ()

于是:

let tbl = dict [(1, "one"); (2, "two");]

tbl.if_has_key 1 (fun val->
    print_any val |>ignore)

可是fun关键字实在扎眼,也只能感叹Ruby的设计至少在格式层面是很巧妙的了。第二种方法利用F#的active pattern功能:

let (|HasKeyVal|_|)<'kt, 'vt> k (d:System.Collections.Generic.IDictionary<'kt, 'vt>)  =
    if d.ContainsKey k then Some(d.[k])
    else None

于是:

match tbl with
| HasKeyVal 2  v -> print_any v
| _ -> ()

缺点一是match关键字在这个地方不伦不类,二是要跟个尾巴|_->() 。好处是可以像swich包含多个case一样:

match tbl with
| HasKeyVal k1 v -> ...
| HasKeyVal k2 v -> ...
| HasKeyVal k3 v -> ...
| _-> ()

程序会依次测试tbl是否包含k1,k2,k3。这样的程序对比起用if...then...elseif...else写出来的版本节省就比较可观了。

你可能感兴趣的:(F#)