有没有从应用模式匹配功能,在停止斯卡拉任何根本性的限制?(Is there any fundamen

2019-08-16 21:31发布

在像SML,Erlang的语言和他人的布赫,我们可以这样定义功能:

fun reverse [] = []
|   reverse x :: xs  = reverse xs @ [x];

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

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

但我不知道,如果我们可以用Scala编写代码前,也许脱糖后者。

是否有这样的语法的基本限制在未来( - 例如,道路类型推断在Scala中,或别的什么工作,除了解析器很明显,我的意思是,真正的基础)正在实施?

UPD
这里是它如何可能看起来像一个片段:

type T
def reverse(Nil: List[T]) = Nil
def reverse(x :: xs: List[T]): List[T] = reverse(xs) ++ List(x)

Answer 1:

这真的取决于你的意思是什么根本

如果你真的问:“ 如果有一个技术性搅局者,将阻止实现此功能 ”,那么我会说答案是否定的。 你说的是脱糖,和你是在正确的轨道上。 所有有做的是从根本上缝几个分离的情况下为一个单一的功能,这可以作为一个纯粹的预处理步骤(这个只需要语法知识,不需要语义知识)来完成。 但对于这甚至是有意义的,我会定义一些规则:

  • 函数签名是强制性的(在Haskell举例,这将是可选的,但它始终是可选无论您是在定义一次或几部分功能)。 我们可以尽量安排生活没有签名,并尝试从不同的部分提取出来,但缺少的类型信息将很快来到我们字节。 一个更简单的说法是,如果我们要尝试推断隐含的签名,我们不妨做它的所有方法。 但事实是,有有在Scala中明确singatures很好的理由,我无法想象改变这种状况。
  • 所有部件都必须在同一范围内定义。 首先,他们必须在同一个文件中声明,因为每一个源文件被单独编译,因此一个简单的预处理器是不够的,以实现该功能。 其次,我们还是结束了在最后一个方法,所以这是很自然的在同一范围内的所有部件。
  • 超载是不可能这样的方法(否则我们就需要重复签名的哪部分属于哪个超载只是这样的预处理器知道每个部分)
  • 份加入( 缝合 ),以将所生成的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)

这可能是平凡转化为:

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...

这是很容易看到的是,上述转化是非常机械,并且可以通过只操纵源AST(通过接受这个新的构建体的稍微修改的语法产生的AST),并将其转变成由产生的目标AST(AST的做标准Scala语法)。 然后,我们可以编译的结果一切正常。

所以你去,有一些简单的规则,我们是能够实现的预处理器做所有的工作来实现这一新功能。


如果根本你问“ 有没有任何让这个功能格格不入 ”,那么可以说,这不会觉得很阶 。 但更重要的是,它并没有带那么多表。 Scala的作者(S)实际上趋向使语言更简单(如在更短的内置功能,尝试一些内置的功能转移到库),并增加了新的语法,是不是真的更具有可读性违背了简化的目的。



Answer 2:

在SML,您的代码段是从字面上只是语法糖(“派生出来的形式”中的语言规范的术语)

val rec reverse = fn x =>
    case x of [] => []
            | x::xs  = reverse xs @ [x]

这是非常接近向你展示Scala代码。 因此,无论有没有“根本”原因,斯卡拉不能提供同样的语法。 主要的问题是Scala的需要更多类型的注释,这使得这个语法速记远不如吸引力一般,而且很可能不值得的。

还需要注意的是你建议的特定语法不会飞得好,因为没有办法区分语法两个重载函数一个案件逐案函数定义。 你可能会需要一些替代语法,与SML使用“ | ”。



Answer 3:

我不知道SML或二郎,但我知道哈斯克尔。 这是一个没有方法重载的语言。 方法重载这样的模式匹配相结合可能会导致歧义。 想象一下下面的代码:

def f(x: String) = "String "+x
def f(x: List[_]) = "List "+x

应该是什么意思? 它可以指方法重载,即方法是在编译时确定的。 这也意味着模式匹配。 会有只是AF(X:AnyRef),会做的匹配方法。

斯卡拉也已命名的参数,这也将可能打破。

我不认为Scala是能够提供更简单的语法比你一般的显示。 一个简单的语法可以仅在一些特殊情况下恕我直言工作。



Answer 4:

至少有两个问题:

  1. [] ,因为它们被用于类型参数被保留字符。 编译器允许他们周围的空间,所以这不会是一个选项。
  2. 另一个问题是, =返回Unit 。 打完表达| 不会返回任何结果

我能想出最接近的是这(注意,这是非常专业对你的例子):

// Define a class to hold the values left and right of the | sign
class |[T, S](val left: T, val right: PartialFunction[T, T])

// Create a class that contains the | operator
class OrAssoc[T](left: T) {
  def |(right: PartialFunction[T, T]): T | T = new |(left, right)
}

// Add the | to any potential target
implicit def anyToOrAssoc[S](left: S): OrAssoc[S] = new OrAssoc(left)

object fun {

  // Use the magic of the update method
  def update[T, S](choice: T | S): T => T = { arg =>
    if (choice.right.isDefinedAt(arg)) choice.right(arg)
    else choice.left
  }
}

// Use the above construction to define a new method
val reverse: List[Int] => List[Int] =
  fun() = List.empty[Int] | {
    case x :: xs => reverse(xs) ++ List(x)
  }

// Call the method
reverse(List(3, 2, 1))


文章来源: Is there any fundamental limitations that stops Scala from implementing pattern matching over functions?