2012-03-29 9 views
8

Po niedawnym obejrzeniu prezentacji Clojure Protocols, byłem pod wrażeniem tego, w jaki sposób można w ten sposób rozszerzyć istniejące typy. Byłem jednak pewien, że już widziałem podobny sposób robienia tego w jakimś innym języku i po pewnym czasie dowiedziałem się, że to Groovy Categories.Różnice między Protokołami Clojure i Groovy Kategorie

Porównaj to:

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

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

do równowartości Clojure Protocol (zaczerpnięte z mikera's answer below and tested in ideone.com)

(defprotocol Lowerable 
    (lower [x])) 

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

(println (lower "HELLO")) 

moje pytanie brzmi:

  1. oprócz różnic wydajności (mówi się, że Clojure jest wysoce zoptymalizowany pod tym względem) - czy istnieje różnica semantyczna między tymi dwiema metodami ches?
  2. oprócz niezgrabnej składni, czy jest coś logicznie nie tak z podejściem Groovy?

Nota prawna: Jestem kompletnym nowicjuszem Clojure!

+0

Uważam to pytanie za dość interesujące. Czy mógłbyś dodać ekwiwalent Clojure'a dla nie oświeconego nas Clojure i dla porównania składni/zwięzłości? : D – epidemian

+0

Przepraszam, chciałbym, po prostu nie mogę. Na stronie http://clojure.org/protocols istnieje dość podobna próbka, ale teraz nie mogę przetestować równoważnego kodu, dlatego nie chcę publikować kodu, który może nie działać. Niestety, nie ma konsoli internetowej, takiej jak konsola internetowa Groovy (jest jedna na try-clojure.org, ale nawet nie wklejałem w newline oddzielnych linii kodu). – Ice09

+0

Może spróbuj z [ideone] (http://ideone.com/)? – epidemian

Odpowiedz

10

Oto szorstki odpowiednik kodu Clojure użyciu protokołów:

(defprotocol Lowerable 
    (lower [x])) 

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

(lower "HELLO") 
=> "hello" 

Kluczowe wyróżnienia pamiętać o protokołach Clojure (które wierzę uczynić go charakterystyczny z Groovy kategorii Version)

  • Protokołu Clojure definicja nie zawiera żadnych implementacji (bardziej przypomina interfejs w tym zakresie). Implementacja jest dostarczana osobno: możesz rozszerzyć protokół Opuszczalne na dowolną liczbę klas, bez potrzeby wprowadzania jakichkolwiek zmian w samych klasach lub w definicji protokołu. Na przykład możesz zdefiniować lower do pracy na Rope.
  • Twoja kategoria Groovy jest przeznaczona dla Strings - tak nie jest w przypadku protokołów Clojure. W tym przykładzie definiowany jest protokół Clojure "Opuszczalne", nie mówiąc nic o typie argumentów.
  • lower jest prawidłową funkcją pierwszej klasy. Możesz więc użyć go do budowania abstrakcji wyższego rzędu (poprzez funkcje wyższego rzędu), które z kolei przyjmą dowolne argumenty, do których został przedłużony Protokół Niskich Rozmiarów.
  • Protokoły Clojure są silnie zoptymalizowane, ponieważ zostały zaprojektowane z myślą o wykorzystaniu szybkiej metody wysyłki JVM.dlatego uzyskać skompilowany w dół do bardzo wydajnego kodu (nie ma dynamiczne badanie przedmiot lub odbicie wymagane)

protokoły Clojure są rzeczywiście dość wyjątkowa solution to the Expression Problem (powiązany film jest bardzo ciekawe). Myślę, że najbliższym odpowiednikiem protokołów Clojure w innym języku są w rzeczywistości klasy typu Haskell. Nawet wtedy jest to trochę trudniejsze, ponieważ Haskell jest statycznie wpisany, a Clojure jest dynamicznie wpisywane ...

+0

Dzięki, to miłe wyjaśnienie, o różnych implementacjach faktycznie jest większa moc. Muszę jednak wypróbować podejście {{Mieszanie}}, {{Delegata}} i {{Kategoria}}, ale nawet gdyby to zadziałało, wydaje się, że aplet Protokołów wydaje się być bliżej. Nie mam nic przeciwko temu, żebym rozszerzył moje pytanie o twoje rozwiązanie (i dodany println) w idee-Link w celu wyjaśnienia. – Ice09

5

Funkcja Clojure on powołując się wygląda następująco:

(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 

implementacje mogą być dodawane do każdego rodzaju w każdej chwili - nie ma potrzeby obu implementacjach pisałem współpracować w jakikolwiek sposób.

Nie rozumiem jednak Groovy na tyle dobrze, aby przedstawić merytoryczne komentarze na temat samego pytania; Mogę tylko pomóc opisać stronę Clojure pytania.

+0

Przyjemny krótki egzemplarz, aby zademonstrować punkt. – Ice09

Powiązane problemy