Pergunta

Na verdade, estou lendo o livro para se divertir, mas pode ser considerado lição de casa. Em todo o caso, eu não me sinto confortável com variáveis ??de estado local a todos com essa linguagem ... Tome por exemplo este código:

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

Por que esta alternativa de código entre 1 e 0? contagem é dado o valor de 0 cada vez que esta função é chamado! A python equivalente seria:

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

Isso retorna a mesma coisa de cada vez. Estou confuso ...

Foi útil?

Solução

Eu tenho um pouco de experiência com a escrita de compiladores para linguagens funcionais, então talvez uma breve descrição de como essa função é armazenado / representados na memória está em ordem. Cada função pode aproximadamente ser pensado como um par (E, F) onde E é o conjunto de variáveis ??livres, e F é o "código" da própria função. Quando você chamar a função, que leva os valores E e substitui aqueles em para as variáveis ??em F, e, em seguida, executa o código usando esses valores.

Assim, onde o seu exemplo está em causa, você definiu a variável "flip" para ser a função retornado por sua expressão let. Essa função é o material dentro do seu lambda. Porque "contagem" é definido fora do lambda, é uma variável livre, então ele é armazenado no ambiente da função. Então, toda vez que você ligar para (FLIP), o intérprete vai para o código no lambda, vê que ele precisa olhar para cima o valor de "contagem" no ambiente, faz isso, muda-lo, e retorna. É por isso que cada vez que você chamá-lo, o valor armazenados em "contar" persiste.

Se você quer contar até ser zero cada vez que você chamar aleta, coloque a expressão let dentro do lambda, por isso é uma variável ligada em vez de uma variável livre.

Outras dicas

O lambda é um fechamento. É uma função que faz referência a uma variável livre (count), que, não sendo definidos localmente ou um dos parâmetros, está vinculado ao ambiente léxico colocando mais próximo.

A função a ser chamado é o lambda, não "flip". Flip é apenas um nome que você deu ao lambda que é retornado para fora da (vamos ...) expressão.

Como para o Python, eu não sei o idioma, mas parece que a contagem deve ser um membro do objeto Flip, não uma variável local para chamada .

Porque a sua função aleta realmente retorna uma função (que é definida dentro de lambda)

Cada vez que você chamar a função retornou ele modifica seu ambiente.

Se você pensar sobre isso o deixe cria o ambiente (e inicializa contar a 0) apenas uma vez -. Quando a função lambda é devolvido para você

Em um lambda sentido cria um objeto de função para você que usa ambiente, cujo último quadro foi inicializado em deixe com uma única contagem variável. Cada vez que você chamar sua função modifica seu ambiente. Se você chamar aleta uma segunda vez ele retorna outro objeto função com ambiente diferente. (Contagem inicializado a 0) Você pode, em seguida, alternar os dois functors independente.

Se você quiser undestand totalmente como ele funciona você deve ler sobre modelo environmantal .

é mais 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

Atualização com mais explicação: A função no Esquema é uma tampa que fecha "" em torno do count variável livre, que é definido no âmbito do lado de fora. A maneira que count é definido em um let com apenas a função de como o corpo, significa que a função é a única coisa que pode acessá-lo -. Fazer count efetivamente uma espécie de estado mutável privada que está ligado à função

Este é o caminho "objetos" são tradicionalmente criado no esquema em SICP - ter um let definir um monte de variáveis ??(as variáveis ??de instância, inicializados para seus valores iniciais) e no corpo definir um monte de funções que são "métodos" que têm acesso compartilhado para as variáveis ??de instância. É por isso que é natural aqui para usar uma classe Python para representar o que está acontecendo, com count sendo uma variável de instância.

Uma tradução mais literal em Python 3.x seria algo como isto (note que é apenas aproximada como Python não tem uma let (escopo limitado locais declaração de variável) sintaxe e lambdas do Python não pode ser usado porque eles não tomam declarações):

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

O problema com o código original é que ele tem uma forte influência do estilo imperativo. Uma solução mais idiomática será:

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

Para responder à pergunta em você comentário ooboo, você quer uma função que retorna uma função

(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))))

Você pode trivialmente alterar o conjunto! linha para que ele se torna um contador, não um flipper (mais útil).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top