pronunciation language scheme

language - scheme synonym



Diferencia entre define, let y set! (4)

¿Quiere decir (+ 1 a) lugar de (1+ a) ? El último no es sintácticamente válido.

El alcance de las variables definidas por let están vinculadas a este último, por lo tanto

(define (f x) (let ((a 1)) (+ a x)))

es sintácticamente posible, mientras

(define (f x) (let ((a 1))) (+ a x))

no es.

Todas las variables deben define d al comienzo de la función, por lo tanto, es posible el siguiente código:

(define (g x) (define a 1) (+ a x))

mientras que este código generará un error:

(define (g x) (define a 1) (display (+ a x)) (define b 2) (+ a x))

porque la primera expresión después de la definición implica que no hay otras definiciones.

set! no define la variable, sino que se usa para asignar a la variable un nuevo valor. Por lo tanto, estas definiciones no tienen sentido:

(define (f x) (set! ((a 1)) (+ a x))) (define (g x) (set! a 1) (+ a x))

¡Uso válido para el set! es como sigue:

(define x 12) > (set! x (add1 x)) > x 13

Aunque se desaconseja, Scheme es un lenguaje funcional.

Ok, esta es una pregunta bastante básica: estoy siguiendo los videos del SICP, y estoy un poco confundido acerca de las diferencias entre define , let y set! .

1) De acuerdo con Sussman en el video, define permite adjuntar un valor a avariable solo una vez (excepto cuando está en REPL), en particular dos define en línea no están permitidos. Sin embargo, Guile felizmente ejecuta este código

(define a 1) (define a 2) (write a)

y salidas 2, como se esperaba. Las cosas son un poco más complicadas porque si trato de hacer esto (EDIT: después de las definiciones anteriores)

(define a (1+ a))

Me sale un error, mientras

(set! a (1+ a))

esta permitido. ¡Todavía no creo que esta sea la única diferencia entre set! y define : ¿qué es lo que me estoy perdiendo?

2) La diferencia entre define y let me intriga aún más. Sé que, en teoría, let se utiliza para vincular variables en el ámbito local. Aún así, me parece que esto funciona igual con define , por ejemplo, puedo reemplazar

(define (f x) (let ((a 1)) (+ a x)))

con

(define (g x) (define a 1) (+ a x))

f y g funcionan igual: en particular, la variable a se libera fuera de g también.

La única forma en que puedo ver esto útil es que puede tener un alcance más corto que la definición de toda la función. Aún así, me parece que siempre se puede agregar una función anónima para crear el alcance necesario e invocarlo de inmediato, al igual que hace uno en JavaScript. Entonces, ¿cuál es la verdadera ventaja de let ?


Es posible que pueda usar define más de una vez, pero no es idiomático: ¡ define implica que está agregando una definición al entorno y set! implica que estás mutando alguna variable.

No estoy seguro acerca de Guile y de por qué permitiría (set! a (+1 a)) pero si a aún no está definido eso no debería funcionar. Por lo general, uno usaría define para introducir una nueva variable y solo mutarla con el set! luego.

Puede utilizar una aplicación de función anónima en lugar de let , de hecho, eso es generalmente lo que let expandirse, casi siempre es una macro. Estos son equivalentes:

(let ((a 1) (b 2)) (+ a b)) ((lambda (a b) (+ a b)) 1 2)

La razón por la que usaría let es porque es más clara: los nombres de las variables están justo al lado de los valores.

En el caso de las definiciones internas, no estoy seguro de que Yasir tenga razón. Al menos en mi máquina, ejecutar Racket en modo R5RS y en modo regular permitió que las definiciones internas aparezcan en el medio de la definición de la función, pero no estoy seguro de lo que dice la norma. En cualquier caso, mucho más tarde en el SICP, se analiza en profundidad el truco que define la pose interna. En el Capítulo 4, se explora cómo implementar las definiciones internas mutuamente recursivas y lo que significa para la implementación del intérprete metacircular.

¡Así que quédate con eso! SICP es un libro brillante y las conferencias en video son maravillosas.


La respuesta de John Clements es buena. En algunos casos, puede ver en qué se convierten las define en cada versión de Scheme, lo que puede ayudarlo a comprender lo que está sucediendo.

Por ejemplo, en Chez Scheme 8.0 (que tiene sus propias peculiaridades de define , especialmente wrt R6RS!):

> (expand ''(define (g x) (define a 1) (+ a x))) (begin (set! g (lambda (x) (letrec* ([a 1]) (#2%+ a x)))) (#2%void))

¡Usted ve que la definición de "nivel superior" se convierte en un set! (¡aunque solo expandir define en algunos casos cambiará las cosas!), pero la definición interna (es decir, una define dentro de otro bloque) se convierte en un letrec* . Los diferentes Esquemas expandirán esa expresión en diferentes cosas.

MzScheme v4.2.4 :

> (expand ''(define (g x) (define a 1) (+ a x))) (define-values (g) (lambda (x) (letrec-values (((a) ''1)) (#%app + a x))))


Su confusión es razonable: ''dejar'' y ''definir'' crean nuevos enlaces. Una ventaja de ''dejar'' es que su significado está extraordinariamente bien definido; no hay absolutamente ningún desacuerdo entre varios sistemas Scheme (incluido Racket) acerca de lo que significa "dejar pasar".

La forma ''definir'' es una olla diferente de pescado. A diferencia de ''let'', no rodea el cuerpo (región donde el enlace es válido) con paréntesis. Además, puede significar cosas diferentes en el nivel superior e internamente. Los diferentes sistemas de esquemas tienen significados dramáticamente diferentes para ''definir''. De hecho, Racket ha cambiado recientemente el significado de ''definir'' al agregar nuevos contextos en los que puede ocurrir.

Por otro lado, a las personas les gusta ''definir''; tiene menos indentación, y generalmente tiene un nivel de alcance "do-what-I-mean" que permite definiciones naturales de procedimientos recursivos y mutuamente recursivos. De hecho, me picó esto el otro día :).

Finalmente, ''set!''; como ''let'', ''set!'' es bastante sencillo: muta una unión existente.

FWIW, una forma de entender estos ámbitos en DrRacket (si lo está usando) es usar el botón "Comprobar sintaxis", y luego pasar el cursor sobre varios identificadores para ver dónde están enlazados.