2013-10-27 11 views
9

Quello che mi ha fatto pensare è stato il motivo per cui il seguentePerché la corrispondenza in Scala è stata implementata come parola chiave piuttosto che come metodo?

<something> match { ... } 

non potrebbe essere riscritto come

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

Credo che sia perché non sarebbe stato possibile realizzare match come metodo normale, ma io non sono sicuro O forse era per motivi di prestazioni.

Inoltre, ora che le macro sono disponibili, sarebbe possibile implementare match utilizzando una macro? (non che dovrebbe essere fatto, ma solo ipoteticamente)

MODIFICA: Questo sembra correlato ad es. What is scala's experimental virtual pattern matcher?; grazie a @ om-nom-nom per averlo indicato.

+0

C'è qualche vantaggio nel rendere la corrispondenza implementata tramite macro? Soprattutto dato che esiste un * modello di corrispondenza virtualizzato *? –

+0

@ om-nom-nom: non so - ho fatto la domanda per scopi di apprendimento/comprensione; ma chissà, rimuovere casi speciali a volte ha inizialmente benefici non ovvi. Inoltre, non sapevo nulla di * virtualized pattern matching * finora, ma lo sto verificando ora. –

+0

@ om-nom-nom: basato su ciò che ho appena imparato da http://stackoverflow.com/questions/8533826/what-is-scalas-experimental-virtual-pattern-matcher, risponderei "sì" a la seconda parte della tua domanda. –

risposta

2

Avendo come parola chiave, non è necessario associarlo al tipo Qualsiasi, quindi il compilatore è libero di dedurre il tipo di input della funzione (parziale). Se fosse un metodo di Any, avrebbe preso come argomento una funzione [A, B].

Le implicazioni pratiche sono che

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

causa l'compilazione errore 'tipo non corrispondente'

tuttavia il (tipo paramerterless) matchMethod;

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

fa sì che il runtime eccezione 'scala.MatchError'

allora anche se ci verbosely paramerterized esplicitamente i tipi che ancora non sarebbe un errore di compilazione per la seguente situazione:

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

piuttosto otterremmo l'eccezione di runtime 'java.lang.ClassCastException' come sotto la cappa dovremmo usare .asInstanceOf.

L'altro bonus è l'evidenziazione della sintassi, gli abbinamenti saltano fuori nel codice più che ancora un altro metodo, che credo meriti come l'abbinamento di modelli è una parte così importante di Scala che merita un'attenzione speciale.

AGGIUNTA: per ragioni simili, si desidera provare a essere un costrutto di parole chiave anziché una funzione che utilizza due funzioni come parametri. la corrispondenza è quindi coerente con la cattura, che è anche coerente con Java.

Questa risposta è un'espansione su Martin Odersky di, che è stato sottolineato da TravisBrown

+1

Non sono d'accordo con il limite dichiarato dell'inferenza di tipo. È banale creare una classe implicita che consenta la corrispondenza di modelli sicuri per tipo: 'classe implicita MatchOps [A] (privato val a: A) estende AnyVal { def m1 [B] (pf: PartialFunction [A, B]): B = pf.applyOrElse (a, genera un nuovo MatchError (a)) def m2 [B] (pf: Funzione parziale [A, B]): Opzione [B] = pf.lift.apply (a) } Qui m1 agisce come la parola chiave 'match' corrente mentre m2 sarebbe simile a un' matchOption' – megri

1

risposta di samthebest è probabilmente la vera ragione (non so, non è una cosa che conosco bene), ma c'è un altro modo di guardarlo che si riferisce alla programmazione funzionale più in generale.

E 'ben noto che corrisponde nella programmazione funzionale può essere fatto senza alcuna lingue particolari caratteristiche (Church Encoding)

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

In questa interpretazione, quando si scrive

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

la parola sealed è il valore/termine che fornisce la funzione match.

Quindi un modo di leggere la tua domanda è, perché non farlo? Perché non creare corrispondenze con altre funzionalità linguistiche di base anziché fornire una corrispondenza sintattica?

La ragione è che sintattica match fornisce po 'di zucchero sintattico che le persone come:

  • sovrapposte funzione match:

    sealed trait A 
    sealed trait B 
    case object X extends A 
    case object Y extends A with B 
    case object Z extends B 
    
  • nidificate funzione match:

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

    Questo è molto imbarazzante scrivere senza zucchero sintattico. Puoi farlo; Ho provato ad esplorare la possibilità quando trying to implement monadic extractors; ma sicuramente è meno carino.

  • Selezione automatica delle funzioni di incontro aperto e chiuso.

    Cioè, gli estrattori in Scala sono come le funzioni di corrispondenza aperta perché qualsiasi errore può restituire None; il compilatore non verificherà la completezza di match ma puoi concatenare quanti ne vuoi e Scala seleziona il primo. D'altra parte, i tratti sealed forniscono funzioni di corrispondenza chiuse con il vantaggio del controllo di completezza. Questi dovrebbero essere forniti da funzioni separate, ma Scala consente di utilizzare la stessa sintassi match per entrambi.

Personalmente ho il sospetto che i requisiti di cui sopra non richiedano, in definitiva, uno speciale supporto sintattico per le partite. Sospetto che altre caratteristiche linguistiche più generali possano finire per fornire lo stesso vantaggio, in particolare nell'area delle partite annidate. Tuttavia, per il momento è semplicemente più sensato colpire il problema direttamente con una speciale sintassi match.

Problemi correlati