Porównanie dialektów Lispu

Z Wikipedii, wolnej encyklopedii
Przejdź do nawigacji Przejdź do wyszukiwania

Język programowania Lisp ma kilka odmian, różniących się elementami składni, nazywanych dialektami Lispu.

Poniżej przedstawiono poglądowe zestawienie przykładów kodu w języku Lisp, w jego 4 dialektach: Scheme, Emacs Lisp, Common Lisp i Clojure.

Podstawowe stałe symboliczne[edytuj | edytuj kod]

Stałe które występują w każdym Lispie to prawda, fałsz i lista pusta.

Scheme[edytuj | edytuj kod]

  • Prawda - #t
  • Fałsz - #f
  • Lista pusta - ()

Common Lisp i Emacs Lisp[edytuj | edytuj kod]

  • Prawda - t
  • Fałsz - nil
  • Lista pusta - nil, można używać też ()

Clojure[edytuj | edytuj kod]

  • Prawda - true
  • Fałsz - false
  • Lista pusta - nil, można używać też ()

Definicje[edytuj | edytuj kod]

W Scheme i Clojure istnieje tylko jedna przestrzeń nazw obejmujący stałe i funkcje oraz zmienne i zmienne funkcyjne, dzięki czemu w tych dialektach nie trzeba cytować funkcji którą przekazuje się do funkcji wyższego rzędu. W Common Lisp i Emacs Lisp funkcje i stałe traktowane są inaczej, w tych dialektach przekazując funkcję jako parametr należy poprzedzić ją znakami cytowania funkcji (#'). W Clojure parametry funkcji zapisuje się wektorze, za pomocą nawiasów kwadratowych.

Dla przykładu zdefiniujmy stałą 2π oraz funkcję wyższego rzędu, która przekazaną funkcję aplikuje na argumentach 2 i 3.

Scheme[edytuj | edytuj kod]

(define two_pi 6.28318)
(define (apply2_3 f) (f 2 3))

(/ two_pi 3.14159)
;; 2.0
(apply2_3 +)
;; 5
(apply2_3 >)
;; #f

Common Lisp[edytuj | edytuj kod]

Istnieją osobne systemy definiowania funkcji i definiowania stałych. Funkcje przekazywane jako argumenty trzeba poprzedzić #'

(defconstant two_pi 6.28318)
(defun apply2_3 (f) (funcall f 2 3))

(/ two_pi 3.14159)
;; 2.0
(apply2_3 #'+)
;; 5
(apply2_3 #'>)
;; nil

Emacs Lisp[edytuj | edytuj kod]

(defconst two_pi 6.28318)
(defun apply2_3 (f) (funcall f 2 3))

(/ two_pi 3.14159)
;; 2.0
(apply2_3 #'+)
;; 5
(apply2_3 #'>)
;; nil

Clojure[edytuj | edytuj kod]

(def two_pi 6.28318)
(defn apply2_3 [f] (f 2 3))

(/ two_pi 3.14159)
;; 2.0
(apply2_3 +)
;; 5
(apply2_3 >)
;; false


Operacje na listach[edytuj | edytuj kod]

We wszystkich dialektach jest możliwe posługiwanie się podstawowymi operacjami:

  • Konstruktor listy pustej: ()
  • Konstruktor listy z pary głowa ogon: (cons głowa ogon)
  • Bezpośrednia konstrukcja listy: '(element1 element2 element3 element4)
  • Pobranie głowy: (car lista), w Clojure: (first lista)
  • Pobranie ogona: (cdr lista), w Clojure: (rest lista)

Zdefiniowane są też zwykle kombinacje dwóch do czterech car i cdr postaci, czytane z prawej do lewej, np.:

  • (cadr '(1 2 3))
  • (car (cdr '(1 2 3)))
  • (car '(2 3))
  • 2

Różnią się one traktowaniem listy nie zawierającej wystarczająco dużo argumentów - w Scheme jest to błąd, w Common Lisp i Emacs Lisp zwracany jest nil.

W Common Lisp i Emacs Lisp istnieją też aliasy:

  • first, równy car - pierwszy element listy
  • second, równy cadr - drugi element listy
  • third, równy caddr - trzeci element listy
  • itd., aż do tenth

Funkcje logiczne[edytuj | edytuj kod]

W Scheme oraz Clojure dość konsekwentnie stosuje się zasadę kończenia funkcji zwracających wartości logiczne znakiem zapytania:

(equal? 3 4)
;; #f
(equal? 4 4)
;; #t

Czego nie robi się w innych omawianych Lispach:

(equal 3 4)
;; nil
(equal 4 4)
;; t

Pytania o typ w Scheme kończą się również znakiem zapytania:

(number? "cztery")
;; #f
(number? 4)
;; #t

Natomiast w innych Lispach literą p:

(numberp "cztery")
;; nil
(numberp 4)
;; t

Funkcje anonimowe i mapowanie list[edytuj | edytuj kod]

Funkcje anonimowe tworzy się za pomocą wyrażenia lambda i stosuje jak normalne funkcje:

(lambda (x) (+ x 1))

((lambda (x) (+ x 1)) 2)
;; 3

Do mapowania w Scheme służy procedura map:

(map (lambda (x) (+ x 1)) '(1 2 3))
;; (2 3 4)

W Clojure do tworzenia funkcji anonimowej stosuje się wyrażenie fn

(map (fn [x] (+ x 1)) '(1 2 3))
;; (2 3 4)

W przypadku dialektów Common Lisp i Emacs Lisp, ze względu na istnienie dwóch przestrzeni nazw (dla zmiennych i funkcji), przekazując procedurę wyższego rzędu jako parametr, należy ją poprzedzić znakami cytatu #'

(defun plus1 (x) (+ x 1))

(mapcar #'plus1 '(1 2 3))
;; (2 3 4)

W przypadku przekazywania do funkcji mapcar jako pierwszy parametr, wyrażenia lambda znaki cytatu są opcjonalne.

(mapcar (lambda (x) (+ x 1)) '(1 2 3))
;; (2 3 4)


Zobacz też[edytuj | edytuj kod]