F# 在F中重写Erlang#

F# 在F中重写Erlang#,f#,erlang,F#,Erlang,我找到了一张Don Syme的照片显示Erlang的 fac(0) -> 1 fac(N) -> N * fac(N-1). 相当于F# 但是,似乎无法在不丢失类型安全性的情况下为不同的算术类型使用模式匹配。例如,可以使用列表模式匹配,但类型必须是公共基类型(例如对象): 考虑到模块中的F#函数不支持重载,看来用静态类型将Erlang代码重写为F#的唯一方法是使用方法重载的静态类,而不是模块。有没有更好的方法在F#中重写具有不同算术性的Erlang函数 一般来说,说Erlang的参

我找到了一张Don Syme的照片显示Erlang的

fac(0) -> 1
fac(N) -> N * fac(N-1).
相当于F#

但是,似乎无法在不丢失类型安全性的情况下为不同的算术类型使用模式匹配。例如,可以使用列表模式匹配,但类型必须是公共基类型(例如
对象
):

考虑到模块中的F#函数不支持重载,看来用静态类型将Erlang代码重写为F#的唯一方法是使用方法重载的静态类,而不是模块。有没有更好的方法在F#中重写具有不同算术性的Erlang函数

一般来说,说Erlang的参数匹配更接近.NET的(包括C#)方法重载而不是F#的模式匹配是正确的吗?或者两者之间没有直接替换,例如,Erlang中可能有一个具有不同算术数的函数+一个保护:

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.

在最后一种情况下,参数的类型不同。你将如何用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
用法:

> foo (One 42);;
val it : string = "42"
> foo (Two (13, 37));;
val it : string = "1337"

显然,你不应该像上面那样定义“愚蠢”的类型,你应该定义一个在你建模的领域中有意义的有区别的联合。

这很好,它还允许使用守卫:
Two(x,y)when x>y
。但是,如果某些参数只是可选的,我很难命名这些情况:例如Default、DefaultWithComparer。。。我需要为每个参数组合命名,这感觉有点奇怪。@V.B.您通常可以通过创建输入类型的默认值来处理默认值。你不必把它当作特例。例如,如果函数始终需要比较器,则将比较器设置为输入类型的必填字段,但随后提供具有默认比较器的该输入类型的默认值,或者提供一个使用默认比较器创建输入值的函数。实际上,这不是我在前面的评论中提到的弱点,而是一种优势:消息传递是Erlang的核心,可以将每个DU案例看作是消息的名称。每个消息都有自己的有线格式,等等。消息的显式命名(尽管冗长)可以在开发/原型阶段增加可读性。然后可以用blittable结构替换它,以避免DU对象分配和序列化。
type MyArguments = One of int | Two of int * int

let foo = function
    | One x -> string x
    | Two (x, y) -> sprintf "%i%i" x y
> foo (One 42);;
val it : string = "42"
> foo (Two (13, 37));;
val it : string = "1337"