Pergunta

Eu estou tentando descobrir como eu posso fazer um "retorno precoce" no procedimento de esquema sem usando um if de nível superior ou cond como construto.

(define (win b)
 (let* ((test (first (first b)))
        (result (every (lambda (i) (= (list-ref (list-ref b i) i) test))
                       (enumerate (length b)))))
  (when (and (not (= test 0)) result) test))
 0)

Por exemplo, no código acima, eu quero win para retorno test se a condição when for atendida, caso contrário retorna 0. No entanto, o que acontece é que o procedimento irá sempre retornar 0, independentemente de o resultado da condição when.

A razão que eu estou estruturar meu código desta forma é porque neste processo eu preciso fazer várias verificações complexos (vários blocos semelhantes ao let* no exemplo) e colocar tudo em uma grande cond seria muito complicado.

Foi útil?

Solução

Aqui está como usar chamada / cc para construir return si mesmo.

(define (example x)
  (call/cc (lambda (return)
    (when (< x 0) (return #f))
    ; more code, including possible more calls to return
    0)))

Alguns esquemas de definir uma macro chamado let / cc que lhe permite deixar cair algum do ruído do lambda:

(define (example x)
  (let/cc return
    (when (< x 0) (return #f))
    0))

É claro que se o seu regime não, deixe / cc é trivial para escrever.


Isso funciona porque chamada / cc salva o ponto em que ele foi chamado como uma continuação. Ele passa ao prosseguimento ao seu argumento de função. Quando a função chama que a continuação, abandona Esquema de tudo o pilha de chamadas que tinha construído até agora e continua a partir do fim da chamada / cc. Claro, se a função nunca chama a continuação, então ele só retorna normalmente.

Continuations não se verdadeiramente alucinante, até você começar a devolvê-los a partir dessa função, ou talvez armazenando-os em uma estrutura de dados global e chamá-los mais tarde. Caso contrário, eles são como declarações Goto estruturado de qualquer outra língua (enquanto / para / break / retorno / continuar / exceções / condições).


Eu não sei o que sua aparência código completo gosta, mas pode ser melhor para ir com o cond e fator das verificações complexas em funções separadas. Precisando return e let* é normalmente um sintoma de código excessivamente imperativo. No entanto, o método de chamada / cc deve obter o seu trabalho de código para agora.

Outras dicas

Uma forma seria usar a recursividade em vez de loop, em seguida, uma saída precoce é alcançado por não recursivo ainda mais.

Você pode usar o "chamada com corrente continuação" suporte para simular um retorno. Há um exemplo na wikipedia . A função é chamada call-com-presente de continuação de , embora muitas vezes há um alias chamado Chamada / cc que é exatamente a mesma coisa. Há também um exemplo um pouco mais limpo aqui

Nota: Esta é completamente uma técnica de programação Esquema avançado e pode ser uma mente pouco dobra no início ... !!!!

Neste caso, você não quer um quando, você quer um caso, ainda que não de nível superior.

(define (win b)
  (let* ((test (first (first b)))
         (result (every (lambda (i) (= (list-ref (list-ref b i) i) test))
                        (enumerate (length b)))))
    (if (and (not (= test 0)) result) 
        test
        0)))

O motivo foi sempre retornando zero é que se deve ou não o corpo do quando tem executado, seu resultado seria cair no chão. Você vê, o lambda implícita na função de definir forma cria um início implícito bloco também, então

(define foo 
  (lambda (b)
     (begin
       (let ...)
       0)))

e a maneira começar obras é que ele retorna o resultado da última forma no interior, ao deixar cair todos os resultados intermediários no chão. Estes resultados intermédios têm a intenção de ter efeitos secundários. Você não está usando nada disso, o que é ótimo (!), Mas você tem que ter cuidado só para ter uma forma (cujo resultado você realmente quer) dentro da definição da função.

Grem

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