Diferença entre avaliação de ordem normal e ordem de aplicação

9

O idioma que estou aprendendo é Scheme e estou trabalhando em um exercício que fornece isso:

(define (p) (p) )

(define (test x y) (if (= x 0)
                               0
                               y))

Em seguida, a pergunta pede para avaliar a expressão: (teste 0 (p)) e comentar sobre o comportamento que seria observado na avaliação de ordem normal e ordem de aplicação.

Estes são os meus pensamentos:

Sob ordem normal, o programa avaliaria as subexpressões antes de prosseguir:

Assim ( test 0 (p) )se torna:

(test 0 p)
( if (= x 0) 0 p))

Saída de retorno 0

A única diferença na ordem do aplicativo seria que o programa fosse executado como:

( test 0 (p) ) torna-se:

(test 0 (p))
( if (= x 0) 0 (p)))

Saída de retorno 0

Assim (p), nunca seria avaliado, pois não será necessário.

Isso está correto? Informe-me, pois quase não tenho experiência em programação.

user224530
fonte
11
Eu senti que a pergunta era geral o suficiente, além da própria linguagem Scheme, para justificar o tratamento aqui.
babou

Respostas:

19

Que pesquisa você fez para responder a essa pergunta? Acabei de ligá-lo como está no Google e recebi como segunda resposta (a primeira pode ser tão boa que não chequei) uma referência a uma seção de uma bíblia sobre seu tópico: Estrutura de Hal Abelson, Jerry Sussman e Julie Sussman e Estrutura e Interpretação de programas de computador (MIT Press, 1984; ISBN 0-262-01077-1), também conhecido como livro dos feiticeiros. A referência é para a seção " Pedido normal e pedido aplicável ".

Afirma:

Scheme é uma linguagem de ordem de aplicativo, a saber, que todos os argumentos para os procedimentos do Scheme são avaliados quando o procedimento é aplicado. Por outro lado, as linguagens de ordem normal atrasam a avaliação dos argumentos do procedimento até que os valores reais do argumento sejam necessários.

e acrescenta que o último é chamado avaliação preguiçosa .

Então você está com suas definições erradas e aceitando uma pela outra:

  • A ordem do aplicativo avalia subexpressões quando, ou seja, logo antes, o procedimento é aplicado.

  • a ordem normal passa as subexpressões como estão, sem avaliação, e prossegue com a avaliação somente quando o parâmetro formal correspondente deve realmente ser avaliado. (há uma reviravolta adicional em relação às questões ambientais ... mas é melhor esquecermos que, neste momento).

Além disso, você não entende adequadamente o mecanismo de chamada que envolve duas coisas:

  • o mecanismo de passagem de parâmetros, que inclui o processamento adequado dos argumentos reais da chamada, dependendo da regra de avaliação;

  • a "substituição" da chamada para a função pelo corpo da função (sem o cabeçalho).

No caso de avaliação de ordem aplicativa de ( test 0 (p) ), você deve avaliar primeiro as sub-expressões do argumento. Estes são 0 e (p).

  • avaliação de um valor literal como 0rendimento esse valor.

  • o segundo argumento, no entanto, é uma chamada de procedimento para um procedimento sem parâmetro chamado p. Não possui parâmetro, para que não tenhamos preocupações com a ordem de avaliação. Então, para prosseguir com a avaliação, precisamos substituir a chamada pelo corpo do procedimento que segue a lista de argumentos e depois avaliar esse corpo. O corpo do procedimento p, conforme definido na declaração (define (p) (p) ), é (p)para que fiquemos com a avaliação do que estávamos tentando avaliar. Em outras palavras, o processo de avaliação é capturado em um loop e não termina.

... e você nunca consegue realmente concluir a chamada para a função test, pois a avaliação de seus argumentos não termina. Seu programa não termina.

Esse risco de não rescisão, mesmo quando o argumento culpado nunca será usado na chamada, é um dos motivos para usar a avaliação normal da ordem, que pode ser um pouco mais difícil de implementar, mas pode ter melhores propriedades de rescisão.

Na avaliação de ordem normal , você não toca nas subexpressões de argumento. O que você faz é substituir a chamada ( test 0 (p) )pelo corpo da função test, ou seja (if (= x 0) 0 y), onde os nomes dos argumentos (formais) xe ysão substituídos pelos correspondentes argumentos reais 0e (p)(até meio ambiente, ou renomear questões, que são importantes, mas que complicam a aqui, e são a principal diferença entre o Lisp original e a linguagem Scheme).

Portanto, você substitui a avaliação de ( test 0 (p) )pela avaliação de (if (= 0 0) 0 (p)).

Agora, a função ifé uma função primitiva que geralmente sempre avalia seu primeiro argumento, mas avalia seus 2 últimos argumentos em ordem normal, avaliando apenas o útil, dependendo se o primeiro avalia como falso ou verdadeiro (atualmente NILou#f por falsa , ou algum outro valor para true , no caso de Scheme - se minha memória não falhar). Como (= 0 0)avalia como verdadeiro , a avaliação do valor condicional para avaliar o segundo argumento ainda não avaliado, ou seja 0, que sem surpresa (exceto no antigo Fortran) avalia 0.

Respiração profunda.

babou
fonte
Eu acho que OP é confundida com a definição no capítulo 1 como por este
SMA