Вот ответ, который определенно не соответствует тому, как вы поступили бы в реальной жизни, но если вы понимаете, что он делает, вы поймете одну из двух важных вещей в Lisps.
(Если вы понимаете, почему эквивалентная программа не будет надежно работать в Scheme, вы также поймете одну из важных вещей, касающихся написания безопасных программ! К счастью, это Common Lisp, а не Scheme, так что здесь все в порядке. )
Прежде всего, давайте напишем небольшую вспомогательную функцию для чтения целых чисел. Это просто мелочь: это не важно.
(defun read-integer (&key (prompt "Integer: ")
(stream *query-io*))
;; Read an integer. This is just fiddly details
(format stream "~&~A" prompt)
(values (parse-integer (read-line stream))))
Хорошо, теперь вот немного странная функция под названием mu
(что означает «мутант U»):
(defun mu (f &rest args)
(apply f f args))
А теперь вот наша программа:
(defun read-integers-until-double-last ()
(mu (lambda (c getter current next factor)
(if (= next (* current factor))
(values current next)
(mu c getter next (funcall getter) factor)))
#'read-integer
(read-integer)
(read-integer)
2))
И вот это работает:
> (read-integers-until-double-last)
Integer: 0
Integer: 4
Integer: 3
Integer: -2
Integer: -4
-2
-4
Для большей таинственности вы можете существенно расширить вызовы mu
здесь, что сделает его либо более ясным, либо менее ясным: я не совсем уверен, какой именно:
(defun read-integers-until-double-last ()
((lambda (c)
(funcall c c
#'read-integer
(read-integer)
(read-integer)
2))
(lambda (c getter current next factor)
(if (= next (* current factor))
(values current next)
(funcall c c getter next (funcall getter) factor)))))
Опять же, это не то, как вы делаете это в реальной жизни, но если вы понимаете, что это делает и как это делается, вы поймете довольно важную вещь о Лиспах и их теоретических основах. Это не все (даже не большинство) интересных вещей о них, но, я думаю, это стоит понять.
person
Community
schedule
29.01.2021