world versiones que programacion programa program lenguaje how hello estructura creo año lisp common-lisp tacit-programming

versiones - programacion en lisp



Programación tácita en Lisp (4)

Podría usar algo como (esto hace un poco más que -> en Clojure):

(defmacro -> (obj &rest forms) "Similar to the -> macro from clojure, but with a tweak: if there is a $ symbol somewhere in the form, the object is not added as the first argument to the form, but instead replaces the $ symbol." (if forms (if (consp (car forms)) (let* ((first-form (first forms)) (other-forms (rest forms)) (pos (position ''$ first-form))) (if pos `(-> ,(append (subseq first-form 0 pos) (list obj) (subseq first-form (1+ pos))) ,@other-forms) `(-> ,(list* (first first-form) obj (rest first-form)) ,@other-forms))) `(-> ,(list (car forms) obj) ,@(cdr forms))) obj))

(debe tener cuidado de exportar también el símbolo $ del paquete en el que coloca -> - llamemos tacit ese paquete - y ponga tacit en la cláusula de use de cualquier paquete en el que quiera usar -> , así que -> y $ son heredados)

Ejemplos de uso:

(-> "TEST" string-downcase reverse) (-> "TEST" reverse (elt $ 1))

Esto es más parecido a F # ''s ( |> (y al shell pipe) que a Haskell''s . , pero son prácticamente lo mismo (prefiero |> , pero esto es una cuestión de gusto personal).

Para ver lo que está haciendo -> , simplemente expanda macro el último ejemplo tres veces (en SLIME, esto se logra colocando el cursor en el primero ( en el ejemplo y escribiendo Cc RET tres veces).

¿Es posible usar / implementar programación tácita (también conocida como programación sin puntos) en Lisp? Y en caso de que la respuesta sea sí, ¿se ha hecho?


Sí, esto es posible en general con las funciones adecuadas. Por ejemplo, aquí hay un ejemplo en la sum implementación de Racket de la página de Wikipedia:

#lang racket (define sum (curry foldr + 0))

Debido a que los procedimientos no se aplican al currículum de manera predeterminada, es útil usar curry o escribir sus funciones en un estilo con currículum explícito. Podría abstraerse sobre esto con una nueva macro de define que utiliza el curry.


SI, es posible y @danlei ya lo explicó muy bien. Voy a agregar algunos ejemplos del libro ANSI Common Lisp de Paul Graham, capítulo 6.6 sobre constructores de funciones:

Puedes definir un generador de funciones como este:

(defun compose (&rest fns) (destructuring-bind (fn1 . rest) (reverse fns) #''(lambda (&rest args) (reduce #''(lambda (v f) (funcall f v)) rest :initial-value (apply fn1 args))))) (defun curry (fn &rest args) #''(lambda (&rest args2) (apply fn (append args args2))))

y usalo asi

(mapcar (compose #''list #''round #''sqrt) ''(4 9 16 25))

devoluciones

((2) (3) (4) (5))

La función de compose llamada:

(compose #''a #''b #''c)

es equlvalente a

#''(lambda (&rest args) (a (b (apply #''c args))))

Esto significa que componer puede tomar cualquier número de argumentos, sí.

Haz una función que agregue 3 al argumento:

(curry #''+ 3)

Ver más en el libro.


Este estilo de programación es posible en CL en principio, pero al ser un Lisp-2, uno tiene que agregar varios #'' s y funcall s. Además, a diferencia de Haskell, por ejemplo, las funciones no se actualizan en CL y no hay una aplicación parcial implícita. En general, creo que tal estilo no sería un CL muy idiomático.

Por ejemplo, podría definir una aplicación parcial y una composición como esta:

(defun partial (function &rest args) (lambda (&rest args2) (apply function (append args args2)))) (defun comp (&rest functions) (flet ((step (f g) (lambda (x) (funcall f (funcall g x))))) (reduce #''step functions :initial-value #''identity)))

(Esos son solo ejemplos rápidos que saqué; no están realmente probados ni bien pensados ​​para diferentes casos de uso).

Con esos, algo como map ((*2) . (+1)) xs en Haskell se convierte en:

CL-USER> (mapcar (comp (partial #''* 2) #''1+) ''(1 2 3)) (4 6 8)

El ejemplo de la sum :

CL-USER> (defparameter *sum* (partial #''reduce #''+)) *SUM* CL-USER> (funcall *sum* ''(1 2 3)) 6

(En este ejemplo, también puede configurar la celda de función de un símbolo en lugar de almacenar la función en la celda de valor, para poder desplazarse por la función).

En Emacs Lisp, por cierto, la aplicación parcial está incorporada como se apply-partially .

En Qi / Shen, las funciones se currifican y se admite la aplicación parcial implícita (cuando se llama a las funciones con un argumento):

(41-) (define comp F G -> (/. X (F (G X)))) comp (42-) ((comp (* 2) (+ 1)) 1) 4 (43-) (map (comp (* 2) (+ 1)) [1 2 3]) [4 6 8]

También hay azúcar de subprocesamiento sintáctico en Clojure que da una sensación similar de "canalización":

user=> (-> 0 inc (* 2)) 2