MoonBit 如何实现类似 multiple dispatch 效果?

之前问过如何实现类似 F# 的 method overloading 效果:

可能 MoonBit 的语法在设计上不太可能支持这个特性,于是在想有没有其他办法实现类似的效果?

之所以还在纠结这个特性是因为平时这种风格的声明式编程写惯了… 包括Python,如果条件允许,我也会 import multipledispatch 这样的第三方实现。

需求说白了就是根据不同的函数签名(同名函数 with 不同的参数目or参数类型)调用不同的函数入口。当然,如果只支持单参数那就没必要了,效果严重打折,dispatch 的多参数支持是必要条件。

Swift 和 F# 用了 overload,Python 虽然不像 Julia 那样原生支持,但可以用装饰器模拟 multiple dispatch。Erlang 虽然不支持OO但通过函数签名+模式匹配解决了这个问题,Elixir 则是在 Erlang 没有 interface 的基础上补充了 Protocols 来进一步完善这方面的特性。

# Example in Elixir
defprotocol P do
  def t(x)
  def t(x,y)
end
defimpl P, for: Integer do
  def t(n) when n>0, do: n+1
  def t(n), do: n
  def t(a,b), do: a+b
end
defimpl P, for: BitString do
  def t(<<_,s::bits>>), do: s
  def t(u,v), do: v<>u
end

IO.puts P.t(-1)  # -1
IO.puts P.t(1)  # 2
IO.puts P.t(2,4)  # 6
IO.puts P.t("123")  # 23
IO.puts P.t("1","2")  # 21

(run :point_up_2:code)

目前 MoonBit 只知道没办法加 overload,但考虑到限制也没有装饰器之类的语法糖,不知道有没有其他可能的方式实现类似的效果?

重名是不可能实现的。不重名可以用trait object

fn main {
  let a : Array[Show] = [1, "a", 3.0]
  for i = 0; i < a.length(); i = i + 1 {
    println(a[i])
  }
}

那以后会有类似装饰器的语法糖吗? @jerry-ye

据我所知短期内应该是不会有了。你具体想要用装饰器的语法糖获得什么效果呢?trait object不够吗?

@jerry-ye 这个要分开讨论,装饰器其实不是必需品,只是装饰器能扩展的出我更偏好的那种声明式写法。

就声明式风格这点讨论,结合文档给出的已知trait的用法,我觉得trait obj比较受限的一点像是fn f[N:T](n:N)这个,方括号里面只能是类型相关的结构引用。

Mojo在这方面做了下改进,允许在[]里面写值变量。这样一来扩展性就非常接近装饰器了(虽然限制在compile-time,但效果不言而喻)。

更接近声明式的写法会让程序的表达更简洁,Elixir可以直接在参数入口做模式匹配来绑定变量,这种形式是目前个人最喜欢的,比起传单个参数再match要直观很多,且易于扩展。

这个也不是必选特性只是加分项,实在没办法可以自己糊一些builder来凑合。但两种风格还是存在一定差异,在一些复杂的场景下写builder时常会打断我的思路,所以用得相对少。