是否有任何基本限制阻止Scala在函数上实现模式匹配?

om-*_*nom 20 syntax functional-programming scala pattern-matching

在像SML,Erlang这样的语言中,我们可以定义这样的函数:

fun reverse [] = []
|   reverse x :: xs  = reverse xs @ [x];
Run Code Online (Sandbox Code Playgroud)

我知道我们可以像这样在Scala中编写模拟(我知道,下面的代码中有很多缺陷):

def reverse[T](lst: List[T]): List[T] = lst match {
  case Nil     => Nil
  case x :: xs => reverse(xs) ++ List(x)
}
Run Code Online (Sandbox Code Playgroud)

但我想知道,如果我们可以在Scala中编写前代码,也许可以放弃后者.

这种语法在未来是否有任何基本限制(我的意思是,真的很基础 - 例如类型推断在scala中的工作方式,或者除了解析器之外的其他东西)?

UPD
以下是它的外观片段:

type T
def reverse(Nil: List[T]) = Nil
def reverse(x :: xs: List[T]): List[T] = reverse(xs) ++ List(x)
Run Code Online (Sandbox Code Playgroud)

Rég*_*les 14

这实际上取决于你的基本意味着什么.

如果你真的在问" 如果有技术的showstopper会阻止实现这个功能 ",那么我会说答案是否定的.你说的是脱贫,你在这里走在正确的轨道上.所有要做的就是将几个分离案例基本上拼接成一个单独的函数,这可以仅仅作为预处理步骤来完成(这只需要语法知识,不需要语义知识).但为了这个甚至有意义,我会定义一些规则:

  • 函数签名是强制性的(在Haskell中,例如,这是可选的,但无论是一次定义函数还是在几个部分定义函数,它总是可选的).我们可以尝试安排在没有签名的情况下生活,并尝试从不同的部分提取它,但是缺少类型信息很快就会出现在我们身上.一个更简单的论点是,如果我们要尝试推断隐式签名,我们也可以为所有方法执行此操作.但事实是,有很好的理由在scala中有明确的单一性,我无法想象要改变它.
  • 必须在同一范围内定义所有部件.首先,它们必须在同一个文件中声明,因为每个源文件都是单独编译的,因此一个简单的预处理器不足以实现该功能.其次,我们最终仍然采用单一方法,因此将所有部件放在同一范围内是很自然的.
  • 这种方法不能进行重载(否则我们需要重复每个部分的签名,以便预处理器知道哪个部分属于哪个重载)
  • 按照声明的顺序将部件添加(拼接)到生成match的部分

所以这是它的样子:

def reverse[T](lst: List[T]): List[T] // Exactly like an abstract def (provides the signature)
// .... some unrelated code here...
def reverse(Nil) = Nil
// .... another bit of unrelated code here...
def reverse(x :: xs ) = reverse(xs) ++ List(x)
Run Code Online (Sandbox Code Playgroud)

这可以简单地转化为:

def reverse[T](list: List[T]): List[T] = lst match {
  case Nil     => Nil
  case x :: xs => reverse(xs) ++ List(x)
}
// .... some unrelated code here...
// .... another bit of unrelated code here...
Run Code Online (Sandbox Code Playgroud)

很容易看出上述转换是非常机械的,可以通过操纵源AST(由接受这种新构造的略微修改的语法产生的AST),并将其转换为目标AST(由AST生成的AST)来完成.标准的斯卡拉语法).然后我们可以像往常一样编译结果.

所以你可以通过一些简单的规则来实现一个预处理器,它可以完成所有工作来实现这个新功能.


如果从根本上说你会问" 有什么东西可以使这个功能不合适 "那么可以说这不会让人感到非常不稳定.但更重要的是,它并没有带来太大的影响.Scala的作者实际上倾向于使语言更简单(如在较少的内置功能中,试图将一些内置功能移动到库中)并添加一种不太可读的新语法违背了简化的目标.


And*_*erg 5

在SML中,您的代码片段实际上只是语法糖(语言规范术语中的"派生形式")

val rec reverse = fn x =>
    case x of [] => []
            | x::xs  = reverse xs @ [x]
Run Code Online (Sandbox Code Playgroud)

这与你展示的Scala代码非常接近.因此,没有没有"基本"原因,Scala无法提供相同类型的语法.主要问题是Scala需要更多的类型注释,这使得这种速记语法在一般情况下的吸引力大大降低,而且可能不值得.

另请注意,您建议的特定语法不能顺利运行,因为无法在语法上区分一个逐个函数的函数和两个重载函数.您可能需要一些替代语法,类似于使用" |"的SML .