2012-03-29 14 views
8

Dopo aver visto di recente una presentazione dei protocolli Clojure, sono rimasto molto impressionato dal modo pulito in cui le estensioni ai tipi esistenti possono essere eseguite in questo modo. Tuttavia, ero abbastanza sicuro di aver già visto un modo simile di farlo in qualche altra lingua e dopo un po 'di tempo ho scoperto che erano le categorie Groovy.Differenza tra protocolli Clojure e categorie Groovy

confrontare questo:

@Category(String) ​class StringCategory { 
    String lower() { 
    return this.toLowerCase() 
    } 
} 

use (StringCategory) { 
    println("TeSt".lower()) 
    assert "test" == "TeSt".lower() 
} 

all'equivalente Clojure Protocol (tratto da mikera's answer below and tested in ideone.com)

(defprotocol Lowerable 
    (lower [x])) 

(extend-protocol Lowerable 
    String 
    (lower [s] 
     (.toLowerCase s))) 

(println (lower "HELLO")) 

la mia domanda è:

  1. oltre da differenze di prestazioni (si dice che Clojure è altamente ottimizzato in questo senso) - c'è una differenza semantica tra i due approa ches?
  2. oltre alla maldestra sintassi, c'è qualcosa di logicamente sbagliato nell'approccio Groovy?

Disclaimer: Sono un novizio Clojure completo!

+0

Trovo questa domanda abbastanza interessante. Potresti aggiungere l'equivalente Clojure per il non clojure-illuminato di noi e per il rispetto dei sintassi/brevità? : D – epidemian

+0

scusate, mi piacerebbe, è solo che non posso. Sul sito http://clojure.org/protocols c'è un campione abbastanza simile, ma al momento non riesco a testare il codice equivalente, quindi non voglio pubblicare del codice che potrebbe non funzionare. Purtroppo, non esiste una console Web come la console Web di Groovy (ce n'è una su try-clojure.org, ma non riesco nemmeno ad incollare righe di codice separate da una nuova riga). – Ice09

+0

Forse prova con [ideone] (http://ideone.com/)? – epidemian

risposta

10

Ecco il codice Clojure equivalente di massima utilizzando i protocolli:

(defprotocol Lowerable 
    (lower [x])) 

(extend-protocol Lowerable 
    String 
    (lower [s] 
     (.toLowerCase s))) 

(lower "HELLO") 
=> "hello" 

Le distinzioni fondamentali da notare su protocolli Clojure (che credo lo rendono distintivo dalla versione categorie Groovy)

  • Il protocollo Clojure la definizione non contiene alcuna implementazione (è più simile a un'interfaccia in questo senso). L'implementazione viene fornita separatamente: è possibile estendere il protocollo Lowerable a tutte le diverse classi che si desiderano senza dover apportare modifiche alle classi stesse o alla definizione del protocollo. Ad esempio, è possibile definire lower per lavorare su un Rope.
  • La tua categoria Groovy di cui sopra è specializzata per le stringhe, questo non è il caso dei protocolli Clojure. In questo esempio, il protocollo Clojure "Lowerable" è definito senza dire nulla sul tipo di argomenti.
  • lower è una funzione di prima classe corretta. Quindi puoi usarlo per creare astrazioni di ordine superiore (tramite funzioni di ordine superiore) che a loro volta accetteranno qualsiasi argomento a cui è stato esteso il protocollo Lowerable.
  • I protocolli di clojure sono fortemente ottimizzati poiché sono progettati per sfruttare l'invio rapido del metodo di JVM.Essi hanno quindi vengono compilati fino al codice molto efficiente (non v'è alcun esame dinamico oggetto o riflessione richiesto)

protocolli Clojure sono in realtà abbastanza unica solution to the Expression Problem (video collegato è piuttosto interessante). Penso che l'equivalente più vicino ai protocolli Clojure in un'altra lingua siano in realtà classi di tipo Haskell. Anche in questo caso è un po 'allungato dal momento che Haskell è tipizzato staticamente e Clojure è digitato dinamicamente ....

+0

Grazie, questa è una bella spiegazione, avere implementazioni diverse in realtà è più potente. Tuttavia, dovrei provare un approccio {{Mixing}}, {{Delegate}} e {{Category}}, ma anche se potrebbe funzionare, la appraoch dei Protocolli sembra più vicina. Ti luppolo non ti spiace che estendo la mia domanda con la tua soluzione (e una stampa aggiunta) in un ideone-Link per chiarimenti. – Ice09

5

La caratteristica Clojure si riferisce a assomiglia:

(defprotocol StringMunging 
    (lower [this])) 

(extend-protocol StringMunging 
    String 
    (lower [this] 
    (.toLowerCase this)) 

    clojure.lang.Keyword 
    (lower [this] 
    (keyword (lower (name this))))) 

user> (lower "TeSt") 
"test" 
user> (lower :TeSt) 
:test 

Le implementazioni possono essere aggiunti a qualsiasi tipo in qualsiasi momento - non c'è bisogno per le due implementazioni che ho scritto a cooperare in qualsiasi modo.

Tuttavia, non capisco abbastanza bene il Groovy per fare commenti sostanziali sulla domanda stessa; Posso solo aiutare a descrivere il lato Clojure della domanda.

+0

Bel breve edxample per dimostrare il punto. – Ice09

Problemi correlati