Pregunta

En realidad estoy leyendo el libro por diversión, sino que podría ser considerada la tarea. En cualquier caso, no me siento cómodo con variables de estado locales en absoluto con este lenguaje ... Tomemos por ejemplo este código:

(define flip
  (let ((count 0))
    (lambda ()
      (if (= 0 count)
          (begin (set! count 1) count)
          (begin (set! count 0) count)))))

¿Por qué este código se alternan entre 1 y 0? recuento se le da el valor de 0 cada vez que esta función se llama! Un equivalente pitón sería:

class Flip:
    def __init__(self):
        pass
    def __call__(self):
        count = 0
        if count == 0:
            count = 1
            return count
        else:
            count = 0
            return count

Esto devuelve el mismo cada vez. Estoy confundido ...

¿Fue útil?

Solución

Tengo un poco de experiencia con los compiladores de escritura para los lenguajes funcionales, por lo que tal vez una breve descripción de cómo se almacena / representada en la memoria es con el fin de que la función. Cada función más o menos puede ser pensado como un par (E, F) donde E es el conjunto de variables libres, y F es el "código" de la propia función. Cuando se llama a la función, que toma los valores de E y sustituye a los de las variables en F, y luego ejecuta el código utilizando dichos valores.

Por lo tanto, en lo que concierne a su ejemplo, ha definido el "flip" variable sea la función que devuelve su expresión let. Esa función es la materia dentro de su lambda. Debido a que "recuento" se define fuera de la lambda, que es una variable libre, por lo que se almacena en el entorno de la función. Entonces, cada vez que llame (FLIP), el intérprete va al código de la lambda, ve que tiene que buscar el valor de "recuento" en el ambiente, hace eso, lo cambia y vuelve. Es por eso que cada vez que la llame, el valor almacenado en el "recuento" persiste.

Si desea contar hasta cero cada vez que llame lado, poner la expresión let dentro de la lambda, así que es una variable ligada en lugar de una variable libre.

Otros consejos

El lambda es un cierre. Es una función que hace referencia a una variable libre (recuento), que, al no estar definida localmente o uno de los parámetros, se une al entorno más cercano léxica que encierra.

La función se llama es la lambda, no "flip". Flip es sólo un nombre que le has dado a la lambda que se volvió de la (y mucho ...) la expresión.

En cuanto a la Python, no sé el idioma, pero parece que la cuenta debe ser un miembro del objeto del tirón, no una variable local a llamada .

Debido a que su función del tirón realidad devuelve una función (que se define dentro de lambda)

Cada vez que se llama a la función devuelta modifica su medio ambiente.

Si se piensa en ello el vamos crea el ambiente (e inicializa contar hasta 0) sólo una vez -. Cuando la función lambda se le devuelve

En un sentido lambda crea un objeto de función para usted que utiliza el medio ambiente, cuya última trama fue inicializado en permitir con un solo cargo variable. Cada vez que se llama a la función que modifica su entorno. Si llama voltear una segunda vez vuelve otro objeto función con diferentes ambientes. (Contar inicializado a 0) A continuación, puede alternar los dos funtores de forma independiente.

Si desea undestand completamente cómo funciona usted debe leer sobre modelo environmantal .

es más como

class Flip:
    def __init__(self):
        self.count = 0
    def __call__(self):
        if self.count == 0:
            self.count = 1
            return self.count
        else:
            self.count = 0
            return self.count

Actualizar con más explicaciones: La función en el Esquema es un cierre que "cierra" alrededor de la count variable libre, que se define en el ámbito de aplicación fuera de ella. La forma en que count se define en una let con sólo la función que el cuerpo, significa que la función es el único que puede acceder a él -. count hacer efectiva una especie de estado mutable privada que se adjunta a la función

Esta es la forma "objetos" son creados tradicionalmente en el Esquema en SICP - tener un let definir un grupo de variables (las variables de instancia, inicializa a sus valores iniciales) y en el cuerpo definen un manojo de funciones que son "métodos" que han compartido el acceso a las variables de instancia. Por eso es natural aquí para utilizar una clase de Python para representar lo que está pasando, con count siendo una variable de instancia.

Una traducción más literal al Python 3.x sería algo como esto (tenga en cuenta que sólo es aproximada como Python no tiene una let (de alcance limitado declaración de variable local) sintaxis y lambdas de Python no se puede utilizar porque no toman declaraciones):

count = 0

def flip():
    nonlocal count
    if count == 0:
        count = 1
        return count
    else:
        count = 0
        return count

# pretend count isn't in scope after this

El problema con el código original es que tiene una fuerte influencia del estilo imperativo. Una solución más idiomática será:

(define (flip)
  (let ((flag #t))
    (lambda ()
      (set! flag (not flag))
      (if flag 1 0))))

Para responder a la pregunta de usted comenta ooboo, que desea una función que devuelve una función

(define make-flipper
  (lambda ()
    (let ((count 0))
      (lambda ()
    (let ((v count))
      (set! count (- 1 count))
      v)))))

;; test it
(let ((flip-1 (make-flipper)))
  (format #t "~s~%" (flip-1))  
  (format #t "~s~%" (flip-1))
  (format #t "~s~%" (flip-1))

  (let ((flip-2 (make-flipper)))
    (format #t "~s~%" (flip-2))
    (format #t "~s~%" (flip-2))
    (format #t "~s~%" (flip-2))))

Puede cambiar el juego de trivial! línea, de modo que se convierta en un contador, no una aleta (más útil).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top