2013-02-10 78 views
20

在像SML,Erlang的語言和他人的布赫,我們可以定義功能,像這樣:是否有任何基本限制阻止Scala實現模式匹配功能?

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) 
+0

你不想這樣寫,因爲這是一個相當低效的「反向」。 – Ingo 2013-02-10 22:31:47

+2

@Ingo這僅僅是一個例子(我已經添加了有關代碼健全性的免責聲明),我可以將factorial作爲示例,它會非常高效。或者你的意思是別的嗎? – 2013-02-10 22:33:36

+0

對我來說,兩者看起來差不多,只是Scala需要參數進行類型註釋,這是OOP/Functional交叉繁殖的結果(與SML中的Hindley-Milner相比)。所以我不完全是你想看到的(除了改變Scala的語法,像'def' - >'fun','Nil' - >'[]') – 2013-02-11 09:53:42

回答

14

這真的取決於你通過根本意思。

如果你真的問「如果有技術性攪局者,將阻止實現此功能」,那麼我會說答案是沒有。你在談論desugaring,你在這裏正確的軌道上。所有有做的是從根本上縫幾個分離的情況下爲一個單一的功能,這可以作爲一個純粹的預處理步驟(這個只需要語法知識,不需要語義知識)來完成。但對於這甚至是有意義的,我會定義一些規則:

  • 函數簽名是強制性的(在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) 

這可能是平凡轉化爲:

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的作者實際上傾向於使語言變得更簡單(就像內置的功能較少,嘗試將某些內置功能移入庫中一樣),並增加一種新語法,這種語法的可讀性並不高,這與簡化的目標背道而馳。

3

我不知道SML或二郎,但我知道哈斯克爾。它是一種沒有方法重載的語言。與這種模式匹配相結合的方法重載可能導致歧義。想象下面的代碼:

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

這是什麼意思?這可能意味着方法重載,即該方法在編譯時確定。它也可以表示模式匹配。只會有一個f(x:AnyRef)方法來進行匹配。

斯卡拉也已命名的參數,這也將可能打破。

我不認爲Scala是能夠提供更簡單的語法比你一般的顯示。一個簡單的語法可能恕我直言,只在一些特殊情況下工作。

3

至少有兩個問題:

  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)) 
5

在SML,您的代碼段是字面上

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

只是語法糖(「派生出來的形式」中的語言規範的術語),這是非常接近你展示Scala代碼。因此,不存在Scala無法提供相同類型語法的「基本」原因。主要的問題是Scala需要更多的類型註釋,這使得這種簡寫語法在總體上遠沒有吸引力,並且可能不值得這個時候。

還請注意,您建議的特定語法不能很好地運行,因爲無法從語法上區分兩種重載函數的個案函數定義。您可能需要一些替代語法,類似於使用「|」的SML。