2013-10-27 7 views
9

Scalaでのマッチは、メソッドではなくキーワードとして実装されたのはなぜですか?

<something> match { ... } 

<something>.match({ ... }) # error: identifier expected but 'match' found. 

のように書き換えることができなかった理由を私は何をして考えてしまった私は、通常の方法としてmatch実装することができなかったであろうからだと思いますが、私わからない。あるいは、パフォーマンス上の理由からかもしれません。

また、マクロが利用できるようになったので、matchは代わりにマクロを使用して実装できますか? (それは行われるべきではないが、仮説的に)

編集:これは、 What is scala's experimental virtual pattern matcher?;それを指摘するために@ om-nom-nomに感謝します。

+0

マクロを使ってマッチを実装するメリットはありますか?特に*に一致する*仮想化パターンがあるとします。 –

+0

@ om-nom-nom:わかりません - 私は学習/理解のために質問しました。しかし、特別なケースを削除することは、当初は明らかではないメリットがあることを知っています。また、私は*仮想化されたパターンマッチング*についてこれまで知りませんでしたが、今のところそれをチェックしています。 –

+0

@ om-nom-nom:私がhttp://stackoverflow.com/questions/8533826/what-is-scalas-experimental-virtual-pattern-matcherから学んだことに基づいて、私は「はい」と答えるでしょうあなたの質問の第二の部分。 –

答えて

2

キーワードとして使用すると、Any型に関連付ける必要がないため、コンパイラは(部分)関数の入力型を自由に推論できます。それがAnyのメソッドだったなら、それは引数として関数[A、B]を取ります。

実用的な意味は

3 match { case "foo" => "bar" } 

コンパイルエラー '型の不一致'

が、(式paramerterless)matchMethodを引き起こすことがあります。

"foo".matchMethod[Int, String] { case 3 => "bar" } 

3.matchMethod { case "foo" => "bar" } 

は、私たちが冗長に明示的に、我々はまだ、次のような状況のためにコンパイルエラーを取得しないでしょうタイプをparamerterizedた場合でも、その後「scala.MatchError」

実行時例外が発生します

ではなく、ランタイム例外 'java.lang.ClassCastException'を使用する必要があります。これは、.asInstanceOfを使用する必要があります。

もう1つのボーナスは構文の強調表示です。パターンマッチングはScalaの重要な部分であり特別な注意を払う必要があると考えています。

追加:同じような理由から、パラメータとして2つの関数をとる関数ではなく、キーワード構造にしようとします。一致はcatchと一貫しており、Javaと一貫しています。

この答えは最初TravisBrownによって指摘されたマーティン・オーダーズキーの上の拡張、ある

+1

私は、型推論の上記の制限に同意しません。 '暗黙のクラスMatchOps [A](プライベートval a:A)は、AnyVal { def m1 [B](pf:PartialFunction [A、B])を継承して、暗黙のクラスを作成するのは簡単です。 ):B = pf.applyOrElse(スロー新しいMatchError(A)) DEF M2 [B](PF:部分写像[A、B]):オプション[B] = pf.lift.apply(A) } ' ここでm1は現在の' match'キーワードとして機能し、m2は 'matchOption'に似ています – megri

1

samthebestの答えはおそらく本当の理由(私は知らない、それは私が精通してるものではないのです)で、より一般的に関数型プログラミングに関連する別の方法があります。

よくあなたが

sealed trait List[+T] 
case object Nil extends List[Nothing] 
case class Cons[+T](head: T, tail: List[T]) extends List[T] 

を書くとき単語sealedは、関数型プログラミングでの試合は、この解釈で

trait List[+T] { 
    def mmatch[R](nil: => R, cons: (T, List[T]) => R): R 
} 
object Nil extends List[Nothing] { 
    def mmatch[R](nil: => R, cons: (Nothing, List[Nothing]) => R) = nil 
} 
class Cons[+T](head: T, tail: List[T]) extends List[T] { 
    def mmatch[R](nil: => R, cons: (T, List[T]) => R) = cons(head, tail) 
} 

def sum(l: List[Int]): Int = l mmatch (
    nil = 0, 
    cons = (x, xs) => x + sum(xs) 
) 

val list = new Cons(1, new Cons(2, Nil)) 

println(sum(list)) 

Church Encoding)特別な言語の機能を使用せずに行うことができることが知られています値/用語はmatch機能を提供します。

あなたの質問を読む1つの方法は、そうするのではなく、なぜですか?統語的なマッチを提供するのではなく、他の基本的な言語機能からマッチを構築してみませんか?

  • 重複マッチ機能:

    sealed trait A 
    sealed trait B 
    case object X extends A 
    case object Y extends A with B 
    case object Z extends B 
    
  • ネストされたマッチ機能:

    (1 :: 2 :: Nil) match { 
        case x :: y :: Nil => ??? 
    } 
    

    これは

    理由は、構文matchは人のように、いくつかの構文糖を提供することです構文的な砂糖なしで書くのは非常に厄介です。あなたはそれを行うことができます。私は可能性を探ってみた。trying to implement monadic extractors;確かにあまりにもかわいいです。

  • オープンとクローズドマッチ機能の自動選択。

    つまり、Scalaのエクストラクタはオープンマッチ関数のようになります。これは、いずれも失敗する可能性があるため、Noneを返します。コンパイラは完全なmatchをチェックしませんが、好きなだけ連鎖させることができ、Scalaは最初のものを選択します。一方、sealed形質は完全一致チェックの恩恵を受けるクローズドマッチ機能を提供する。これらは別々の関数で提供する必要がありますが、Scalaでは両方に対して同じmatch構文を使用できます。

個人的に私は、上記の要件で最終的にマッチのための特別な構文サポートが必要ではないという疑いがあります。私は他のより一般的な言語機能が、特にネストされたマッチの領域で同じ利点をもたらすことになると考えています。しかし当面は、特別なmatch構文を使用して直接問題を突き止めるのが理にかなっています。

関連する問題