Trilhas
/
Common Lisp
Common Lisp
/
Exercícios
/
As sobras da lasanha da Lilly
As sobras da lasanha da Lilly

As sobras da lasanha da Lilly

Exercício de aprendizagem

Introdução

Lista de lambda

Em Common Lisp, a lista de argumentos de uma função é conhecida como 'lista de lambda'. Uma lista de lambda pode ter argumentos de tipos diferentes. Esses diferentes tipos são designados pelo uso de 'palavras-chave de lista de lambda', que começam todas com &. Os tipos mais comuns são os argumentos opcionais, os argumentos de palavra-chave e os argumentos rest. Todo parâmetro na lista de lambda depois de uma determinada palavra-chave de lista de lambda será desse tipo. Uma palavra-chave de lista de lambda só pode ser usada uma vez em uma lista de lambda.

As listas de lambda também são usadas em outras construções que veremos mais adiante, como desestruturação e macros.

Parâmetros opcionais

Em Common Lisp, uma função pode ter alguns argumentos opcionais. Eles são designados na lista de lambda pela palavra-chave de lista de lambda &optional. Um parâmetro será vinculado ao valor nil se não for especificado. Se houver vários parâmetros opcionais, eles são vinculados em ordem. Valores padrão podem ser especificados para parâmetros opcionais. Por fim, pode-se especificar um símbolo para cada parâmetro opcional, que será vinculado a verdadeiro ou falso dependendo de o parâmetro ter sido fornecido ou não por quem chama a função (isso é chamado de "parâmetro supplied-p").

(defun optional-parameters (&optional x (y 'default) (z nil z-supplied-p))
  (list x y (if z-supplied-p (list :z-was-supplied z)
                             (list :z-was-not-supplied z))))

(optional-parameters)          ; => (NIL DEFAULT (:Z-WAS-NOT-SUPPLIED NIL))
(optional-parameters 5 nil 10) ; => (5 NIL (:Z-WAS-SUPPLIED 10))

Parâmetros de palavra-chave

Em Common Lisp, uma função pode ter parâmetros nomeados (chamados de "parâmetros de palavra-chave"). Eles são designados na lista de lambda pela palavra-chave de lista de lambda &key. Parâmetros de palavra-chave não são parâmetros obrigatórios. Assim como os parâmetros opcionais, eles podem receber valores padrão e símbolos para vincular ao seu estado de 'fornecido ou não'.

Ao chamar uma função com parâmetros de palavra-chave, usa-se o nome do parâmetro como palavra-chave na frente do valor do parâmetro. Quem chama a função pode especificar os parâmetros de palavra-chave em qualquer ordem.

(defun keyword-parameters (&key x (y 'default) (z nil z-supplied-p))
  (list x y (if z-supplied-p (list :z-was-supplied z)
                             (list :z-was-not-supplied z))))

(keyword-parameters)            ; => (NIL DEFAULT (:Z-WAS-NOT-SUPPLIED NIL))
(keyword-parameters :y 5)       ; => (NIL 5 (:Z-WAS-NOT-SUPPLIED NIL))
(keyword-parameters :z 10 :x 5) ; => (5 DEFAULT (:Z-WAS-SUPPLIED 10))

É preciso cuidado ao combinar parâmetros opcionais e de palavra-chave, pois o nome da palavra-chave e o argumento podem ser consumidos pelos parâmetros opcionais:

(defun could-be-confusing (&optional x y &key z) (list x y z))
(could-be-confusing :z 'huh?) ; => (:Z HUH? NIL)

Parâmetros rest

Em Common Lisp, uma função pode ter um parâmetro que conterá o "resto" dos argumentos depois que os parâmetros obrigatórios ou opcionais forem processados. Esse parâmetro é designado pela palavra-chave de lista de lambda &rest. Se todos os argumentos de uma função forem usados por outros tipos de parâmetros, o parâmetro rest será vinculado a uma lista vazia. Se houver argumentos não usados, o parâmetro rest será vinculado a uma lista com esses argumentos.

(defun rest-of-it (req &optional opt &rest rest) (list req opt rest))
(rest-of-it 1)         ; => (1 NIL NIL)
(rest-of-it 1 2)       ; => (1 2 NIL)
(rest-of-it 1 2 3)     ; => (1 2 (3))
(rest-of-it 1 2 3 4 5) ; => (1 2 (3 4 5))

Instruções

Lilly, a alienígena do Lisp, com certeza já fez muita lasanha com a sua ajuda. Lilly quer te agradecer dando algumas sobras para você. Mas antes disso, tem um feedback sobre uma das funções que você ajudou a escrever.

Neste exercício, você vai escrever mais algumas funções para ajudar Lilly a cozinhar lasanha e também para dividir as sobras com você.

Você tem seis tarefas: três sobre melhorar as funções de cozinhar lasanha que já existem e três sobre dividir as sobras.

1. Deixe preparation-time-in-minutes mais fácil de usar

Lilly diz que acharam um pouco estranho usar a sua preparation-time-in-minutes, já que era preciso contar todas as camadas antes de usar a função. Lilly quer saber se você poderia fazer uma versão da função que recebe as camadas (quantas forem) como argumentos e depois calcula o tempo de preparo com base em quantas camadas havia? Como lembrete, leva 19 minutos para preparar uma única camada.

(preparation-time 'sauce 'cheese 'right-handed-macaroni 'cheese 'sauce
                  'left-handed-macaroni 'sauce 'sauce 'cheese 'cheese)
                  ;; => 190 (because there are 10 layers.)

2. Permita mudar o tempo esperado no forno

Embora as unidades parentais de Lilly sempre cozinhassem a lasanha por 337 minutos, Lilly admite que outros alienígenas do Lisp gostam de cozinhar a lasanha por mais tempo ou por menos tempo.

Então seria bom se remaining-minutes-in-oven não usasse expected-minutes-in-oven, mas em vez disso pudesse receber um parâmetro opcional para definir se o tempo deve ser mais longo, muito longo, mais curto ou muito curto. Mais longo ou mais curto significa somar ou subtrair 100 do tempo padrão de 337. Muito longo ou muito curto significa somar ou subtrair 200. Se nenhum parâmetro for fornecido, ou se o argumento for 'normal', o valor padrão de 337 deve ser retornado.

(remaining-minutes-in-oven)             ;; => 337
(remaining-minutes-in-oven :normal)     ;; => 337
(remaining-minutes-in-oven :shorter)    ;; => 237
(remaining-minutes-in-oven :very-short) ;; => 137
(remaining-minutes-in-oven :longer)     ;; => 437
(remaining-minutes-in-oven :very-long)  ;; => 537

3. Lilly lembra de outro estilo de cozimento preferido

Logo depois que você terminou essa mudança, Lilly lembra que existem alguns alienígenas do Lisp que gostam de tempos de cozimento bem curtos. Na prática, querem a lasanha crua. Então agora a função deve retornar 0 se o argumento for NIL, além dos mesmos valores da tarefa anterior.

(remaining-minutes-in-oven)     ;; => 337
(remaining-minutes-in-oven nil) ;; => 0

4. Dividindo as sobras

Agora que você ajudou a melhorar as funções de cozinhar lasanha, tem muita lasanha! Lilly quer retribuir toda a sua ajuda dividindo as sobras com você. Você vai precisar escrever uma função que recebe três parâmetros: a quantidade total de sobras, o número de potes para as sobras que Lilly encontrou nos armários e o mesmo para você. Como procurar potes para as sobras pode levar tempos diferentes, e a quantidade exata de sobras pode ser determinada enquanto você e Lilly estão procurando nos armários, vocês dois concordam que a função deve receber os argumentos em qualquer ordem, para que, à medida que cada número for determinado, você possa anotá-lo. Quando tiver os três números, basta fechar o parêntese na chamada da função e avaliá-la.

A função deve retornar a quantidade de sobras que sobram, ou seja, a diferença entre o peso das sobras e o número total de potes que você e Lilly encontraram.

(split-leftovers :weight 20 :human 10 :alien 5) ;; => 5
(split-leftovers :weight 20 :alien 10 :human 2) ;; => 8
(split-leftovers :alien 12 :weight 20 :human 4) ;; => 4

5. Fazendo suposições

Depois de algumas idas e vindas aos seus respectivos armários, vocês dois concordam que seria ótimo se a função pudesse simplesmente assumir que você ou Lilly tinha... digamos, 10 potes, se isso não fosse especificado.

(split-leftovers :weight 20 :human 5) ;; => 5
(split-leftovers :weight 20 :alien 5) ;; => 5
(split-leftovers :weight 20)          ;; => 0

6. Quantidade padrão de sobras

Melhor ainda: a função poderia assumir que há sobras suficientes para caber nos potes. Então, se o peso não for fornecido, a função deve retornar :just-split-it. No entanto, se o peso for fornecido e for nil, deve retornar :looks-like-someone-was-hungry.

(split-leftovers :human 5 :alien 5) ;; => :JUST-SPLIT-IT
(split-leftovers :weight NIL :human 5 :alien 5) ;; => :LOOKS-LIKE-SOMEONE-WAS-HUNGRY
Editar via GitHub O link abre em uma nova janela ou aba
Common Lisp Exercism

Tudo pronto para começar As sobras da lasanha da Lilly?

Crie sua conta no Exercism para aprender e dominar Common Lisp com 27 conceitos92 exercícios e mentoria humana de verdade, tudo de graça.