我找到了Don Syme 的演示文稿,其中显示了Erlang的演示文稿
fac(0) -> 1
fac(N) -> N * fac(N-1).
Run Code Online (Sandbox Code Playgroud)
相当于F#的
let rec fac = function
| 0 -> 1
| n -> n * fac (n-1)
Run Code Online (Sandbox Code Playgroud)
但看起来没有办法在不损失类型安全的情况下为不同的arity使用模式匹配.例如,可以使用列表模式匹配,但是类型必须是公共基类型(例如object
):
let concat = function
| [x;y] -> x.ToString() + y.ToString()
| [x] -> x.ToString()
Run Code Online (Sandbox Code Playgroud)
鉴于在模块F#函数不支持过载,它看起来像改写二郎代码到F#静态类型的唯一方法是使用静态类与方法重载的替代模块.有没有更好的方法在F#中使用不同的arity重写Erlang函数?
在一般情况下,是正确地说,Erlang的参数匹配更接近.NET的(包括C#)方法重载,而不是F#的模式匹配?或者两者之间没有直接的替代,例如在Erlang中可能存在具有不同arities +守卫的功能:
max(x) -> x.
max(x,y) when x > y -> x.
max(x,y) -> y.
max(comparer, x, y) -> if comparer(x,y) > 0 -> x; true -> y end.
Run Code Online (Sandbox Code Playgroud)
在最后一种情况下,参数是不同类型的.你会如何在F#中重写它?
通过稍微重新思考问题,您可以实现接近超载的功能.不要将功能视为可变性轴,而应将输入视为可变部分.如果你这样做,你就会意识到你可以通过一个有区别的联盟达到同样的目的.
这是一个比链接文章中更具人为的例子:
type MyArguments = One of int | Two of int * int
let foo = function
| One x -> string x
| Two (x, y) -> sprintf "%i%i" x y
Run Code Online (Sandbox Code Playgroud)
用法:
> foo (One 42);;
val it : string = "42"
> foo (Two (13, 37));;
val it : string = "1337"
Run Code Online (Sandbox Code Playgroud)
显然,不是像上面那样定义这种"愚蠢"类型MyArguments
,而是定义一个在你正在建模的域中有意义的区别联合.