list - cadr - ¿Cuál es el equivalente del esquema de desempaquetar tuple?
list racket (6)
En Python, puedo hacer algo como esto:
t = (1, 2)
a, b = t
... y a será 1 yb será 2. Supongamos que tengo una lista ''(1 2)
en Esquema. ¿Hay alguna manera de hacer algo similar con let
? Si hace una diferencia, estoy usando raqueta.
Aquí hay una simple macro de destructuring-bind
para esquemas con case-lambda
(como Racket o Chez Scheme):
(define-syntax bind
(syntax-rules ()
((_ arg pat def body)
(apply
(case-lambda
[pat body]
[x def] )
arg ))))
Aquí está el ejemplo que me motivó a escribir esta macro. Poner el valor predeterminado antes de que el cuerpo genere un código legible:
(define (permutations l)
;
(define (psub j k y)
;
(define (join a b)
(bind a (ah . at) b
(join at (cons ah b)) ))
;
(define (prec a b z)
(bind b (bh . bt) z
(prec (cons bh a) bt
(psub (cons bh j) (join a bt) z) )))
;
(if (null? k)
(cons (reverse j) y)
(prec (list) k y) ))
;
(psub (list) (reverse l) (list)) )
Aquí hay puntos de referencia para calcular permutaciones de longitud 9, en varios esquemas:
0m0.211s Chez Scheme
0m0.273s Bigloo
0m0.403s Chicken
0m0.598s Racket
La traducción a GHC Haskell es 5 veces más rápida que el esquema Chez. Guile es mucho más lento que cualquiera de estos esquemas.
Aparte de la facilidad con que se aprovecha el código existente case-lambda
, me gusta cómo esta macro acepta exactamente la misma sintaxis que las listas de argumentos de definición de funciones. Me encanta la simplicidad del esquema. Tengo la edad suficiente para recordar la programación de Fortran en tarjetas perforadas, donde la sintaxis permitida variaba enormemente con el contexto. Se supone que el esquema es mejor que eso. El impulso es abrumador para crear el lirio en macros como esta. Si no puede justificar cambiar también la sintaxis para las definiciones de funciones, entonces tampoco cambie esa sintaxis aquí. Tener una gramática ortogonal es importante.
Creo que esto es lo que estás buscando:
Mira let-values
o let+
.
El término general para lo que estás buscando (al menos en Lisp-world) es desestructuración y una macro que lo implementa se conoce como desestructuración-enlace . En Common Lisp, funciona así:
(destructuring-bind (a b c) ''(1 2 3)
(list a b c)) ;; (1 2 3)
También funciona para múltiples "niveles" de anidación:
(destructuring-bind (a (b c) d) ''(1 (2 3) 4)
(list a b c d)) ;; (1 2 3 4)
Parece que hay una buena implementación de desestructuración-enlace como una macro de esquema.
En la raqueta puedes usar match
,
(define t (list 1 2))
(match [(list a b) (+ a b)])
y cosas relacionadas como match-define
:
(match-define (list a b) (list 1 2))
(match-let ([(list a b) t]) (+ a b))
Eso funciona para listas, vectores, estructuras, etc. Para múltiples valores, define-values
:
(define (t) (values 1 2))
(define-values (a b) (t))
o let-values
. Pero tenga en cuenta que no puedo definir t
como una "tupla", ya que los valores múltiples no son valores de primera clase en la mayoría de las implementaciones de esquemas.
Esto funciona en Racket si no desea traer la dependencia de match
:
De una lista:
(let-values ([(a b c) (apply values ''(1 2 3))])
(+ a b c))
O directamente desde una expresión de valores:
(let-values ([(a b c) (values 1 2 3)])
(+ a b c))
Un lenguaje simple es usar lambda en el lugar en el que usarías, por ejemplo:
(define t ''(1 2))
(apply (lambda (a b)
;; code that would go inside let
)
t)
La ventaja es que funciona en cualquier implementación. Por supuesto, esto solo se puede utilizar en casos simples, pero a veces eso es todo lo que necesita.