Pergunta

Estou seguindo Estrutura e Interpretação de Programas de Computador e ao tentar resolver Ex 1.3 cheguei à seguinte código como minha primeira tentativa:

(define (sumsq a b c)(
(define highest (if (> (if (> a b) a b) (if (> a c) a c)) (if (> a b) a b) (if (> a c) a c)))
(define second_h (if (> (if (> a b) b a) (if (> a c) c a)) (if (> a b) b a) (if (> a c) c a)))
(+ (* highest highest) (* second_h second_h)))

Ele não estava funcionando e eu olhei para a solução e encontrou-os em SICP Wiki

;; ex 1.3
;; implemented using only techniques covered to this point

(define (square x) (* x x))

(define (sum-of-squares x y)
  (+ (square x) (square y)))

(define (largest-two-of-three x y z)
  (if (>= x y)
      (sum-of-squares x (if (>= y z) y z))
      (sum-of-squares y (if (>= x z) x z))))

A diferença era que eu estava usando várias instruções para definir variáveis ??e, em seguida, somar os quadrados, enquanto que a forma correta é definir cada uma das minhas linhas como funções.

são funções no esquema forros? Ou eu perdi a coisa toda?

Foi útil?

Solução

O que você escreveu (menos um parêntese extras) é:

(define (sumsq a b c)
  (define highest
    (if (> (if (> a b) a b)
           (if (> a c) a c))
      (if (> a b) a b)
      (if (> a c) a c)))
  (define second_h
    (if (> (if (> a b) b a)
           (if (> a c) c a))
      (if (> a b) b a)
      (if (> a c) c a)))
  (+ (* highest highest) (* second_h second_h)))

A solução faz praças e soma de quadrados em funções distintas separadas, mas eu não acho que isso é que é importante. Não escrever (+ (* a a) (* b b)) impedi-lo de ter que citar os dois valores você está calculando, que vai deixar você escrever a função como uma grande expressão no final, mas há coisas maiores para se preocupar agora.

Eu acho que o problema que você está tendo é que os seus (se ...) expressões são grandes demais para entender facilmente. Observe que existem dois padrões que aparecem muitas vezes: (if (> a b) a b) e (if (> a b) b a). Estas são as funções máximo e mínimo, por isso, é útil para defini-los como tal:

(define (min a b) (if (< a b) a b))
(define (max a b) (if (< a b) b a))

Desta forma, você pode reescrever a sua solução como:

(define (sumsq a b c)
  (define highest
    (if (> (max a b) (max a c))
      (max a b)
      (max a c)))
  (define second_h
    (if (> (min a b) (min a c))
      (min a b)
      (min a c)))
  (+ (* highest highest) (* second_h second_h)))

Simplificar-lo novamente dá:

(define (sumsq a b c)
  (define highest
    (max (max a b) (max a c)))
  (define second_h
    (max (min a b) (min a c)))
  (+ (* highest highest) (* second_h second_h)))

Observe como esta escrita é muito mais fácil raciocinar com, (max (max a b) (max a c)) é obviamente o máximo de a b e c, e pode realmente ser reescrita como (max (max a b) c). Olhando para second_h, porém, não é óbvio que ele está correto. O que acontecerá quando a é o menor dos três valores?

O truque que eles usam em sua solução é a primeira a comparar x e y. se x < y, então você sabe que y não é o menor dos três, por isso é tanto maior ou segundo maior. O outro número que você vai querer usar é o maior entre x e z, desde o menor dos dois será o menor dos três, o que você deseja ignorar. Lógica semelhante aplica-se quando y < x.

Outras dicas

Você deve usar adequados recuo e quebras de linha para obter uma visão geral sobre o fluxo do programa. Sua primeira proposta, em seguida, lê como este:

(define (sumsq a b c)
  ((define highest 
     (if (> (if (> a b) a b)
            (if (> a c) a c))
         (if (> a b) a b)
         (if (> a c) a c)))
   (define second-h
     (if (> (if (> a b) b a)
            (if (> a c) c a))
         (if (> a b) b a)
         (if (> a c) c a)))
   (+ (* highest highest)
      (* second-h second-h)))

A primeira coisa a aviso: os parênteses não correspondem; existe uma mais aberta do que fechada. mostra uma inspeção cuidadosa que um parêntese de abertura na segunda linha está errado. Esta é, aliás, o que de alguma forma foi pendurada no final de sua primeira linha. Eu arriscaria um palpite de que quando você tentou avaliar isso, nada aconteceu, como o leitor esperava o fim da instrução.

recuo adequada é muito importante. Eu acho que SICP não explicar explicitamente, embora os exemplos são geralmente feito desta forma. Eu encontrei um guia de estilo aqui .

Segundo observação: Você repete-se muito. Em todas essas declarações if aninhados, eu não sou realmente certo se você realmente tem os valores corretos para fora. Olhe para a solução que encontrou para ver como isso pode ser muito simplificada.

Você tentou acabar com a complexidade, dando nomes subresults. Quebrando-se a complexidade é bom, mas é geralmente melhor nome não os resultados, mas os conceitos. Pense no que você faz, em seguida, nomeie essas atividades. Essas são funções, e que constituem a linguagem que você finalmente quase trivialmente resolverá seu problema a.

Uma das ideias de esquema é bottom-up programming onde você cria uma função para cada operação conceitual. Essa é a abordagem recomendada em muitas linguagens de programação funcional.

Com esta abordagem você acaba com um monte de pequenas funções implementação de uma operação lógica nos argumentos. Dessa forma, suas extremidades código por ser muito mais modular e limpo.

A sua solução tinha esta forma: (define (func param) (definir ...) (definir ...))

Mas definir as necessidades desta forma: (define (param func) do corpo)

O corpo é a implementação da função ... o que faz, o que ele retorna. Seu corpo era apenas mais definições, não fazendo nada. Então, isso explica por que sua solução não foi aceita pelo interpretador Scheme.

Para responder à pergunta "são funções de esquema de one-liners?" é preciso investigar o "begin" formulário, que tem esta aparência: (início (+ 1 1) (+ 2 2)) => 4

No exemplo acima, o resultado de (1 1 +) é apenas jogado caminho, então você pode ver que começar realmente só faz sentido quando o interior coisas de que tem efeitos colaterais.

Você deve estar ciente de que algumas partes do Esquema (nomeadamente deixe e lambda) tem implícita começa em torno de seu corpo. Então, isso é válido:

  (let ((x 1))
    (+ 1 1)
    (+ 2 2))

mesmo sem um começar. Isso torna o código mais simples de escrever.

Finalmente, como você continuar a aprender Scheme, sempre tentar encontrar uma maneira de fazer algo sem começa e sem efeitos colaterais. Especialmente nos primeiros capítulos da maioria dos livros Esquema, se você está pensando, "Eu quero definir essa variável, então eu quero fazer isso, então isso ..." você provavelmente está preso em seu velho modo de programação e não fazer -lo da maneira Esquema. Não há nada de errado com efeitos colaterais em tudo, mas o uso pesado deles significa que você não está realmente a programação Esquema do jeito que funciona melhor.

Exercício 1.3 pede-lhe para definir um procedimento que leva três números como argumentos e retorna a soma dos quadrados dos dois números maiores. É fácil definir um procedimento como esse usando o built-in Esquema procedimentos square, max e min, mas nós não encontramos esses procedimentos naquele ponto do livro ainda, então eu defini-los também.

(define (square x)
   (* x x))

(define (max x y)
   (if (> x y) x y))

(define (min x y)
   (if (< x y) x y))

(define (sum-of-highest-squares x y z)
   (+ (square (max x y))
      (square (max (min x y) z))))

O procedimento sum-of-highest-squares funciona através da adição do quadrado do máximo de x e y (o máximo dos dois é eliminado de ser o menor dos três) e o quadrado do máximo dos restantes dois (o mínimo de x e Y, que irá ser qualquer valor foi deixado sobre a partir do primeiro passo), e z.

Nota: Isto é de meu blog SICP Exercícios 1.1 - 1,5 . Há links que irá levá-lo para um monte de outras soluções SICP lá também.

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