在F#中重写Erlang

V.B*_*.B. 6 erlang f#

我找到了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#中重写它?

Mar*_*ann 7

通过稍微重新思考问题,您可以实现接近超载的功能.不要将功能视为可变性轴,而应将输入视为可变部分.如果你这样做,你就会意识到你可以通过一个有区别的联盟达到同样的目的.

这是一个比链接文章中更具人为的例子:

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,而是定义一个在你正在建模的域中有意义的区别联合.

  • @VB您通常可以通过创建输入类型的默认值来处理默认值.你不必把它作为一个特例.例如,如果你的函数*总是*需要一个比较器,那么使比较器成为输入类型的必填字段,但是然后提供具有默认比较器的输入类型的默认值,或者替代,提供*函数*使用默认比较器创建输入值. (2认同)