#racket
#ракетка
Вопрос:
У меня есть вызываемая функция clean-up
, которая в основном выполняет то, что делает уже доступная flatten
функция. Затем у меня вызывается функция multiplier
, которая принимает список и умножает все числа внутри него. Одна проблема заключается в том, что иногда может быть странный синтаксис для списка, используемого в multiplier
, и он не умножает каждое число вместе. Например:
Пример ввода
(multiplier '((1 (2 3)) 4 5 (6)))
Корректный вывод
720
Мой вывод
*: contract violation
expected: number?
given: '(6 . 1)
argument position: 2nd
other arguments...
Теперь нам не нравятся ошибки, не так ли? Эта multiplier
функция работает в обычном списке, что-то вроде (multiplier '(1 2 3 4 5 6))
. Итак, я написал clean-up
функцию, чтобы превратить некоторый запутанный список в обычный список. Однако я не знаю, как вызвать ее, чтобы очистить мой список, прежде чем пытаться выполнить синтаксический анализ и выполнить умножение. Я могу убедиться, что clean-up
функция отлично выполняет свою работу. Кто-нибудь может помочь? Вот код, который у меня есть для обоих:
(define (clean-up s)
(cond [(null? s) '()]
[(not (pair? s)) (list s)]
[else (append (clean-up (car s)) (clean-up (cdr s)))]
))
(define multiplier
(lambda (s)
(cond [(null? s) 1]
[(number? (car s)) (* (car s) (multiplier(cdr s)))]
[list? (car s) (append (car s) (multiplier(cdr s)))]
[else (multiplier (cdr s))]
)))
Ответ №1:
Нет необходимости в clean-up
функции для решения проблем, возникающих в multiplier
. Тем не менее, вы могли бы сначала вызвать clean-up
ввод просто с помощью:
scratch.rkt> (multiplier (clean-up '((1 (2 3)) 4 5 (6))))
720
Или вы можете создать вспомогательную функцию, чтобы сделать это за вас:
(define (multiplier-workaround s)
(multiplier (clean-up s)))
scratch.rkt> (multiplier-workaround '((1 (2 3)) 4 5 (6)))
720
Подобный обходной путь может помочь вам в крайнем случае, но он не устраняет реальные проблемы в коде.
Некоторые из проблем здесь может быть легче увидеть с лучшим форматированием кода. Оставлять висячие круглые скобки в Lisps — плохой стиль, как если бы это были языки в стиле C; но это, вероятно, не вызывает у вас проблем здесь. Тем не менее, это хороший стиль, чтобы показать структуру ваших выражений с помощью отступов. При правильном отступе становится очевидным, что в строке с предикатом отсутствуют круглые скобки list?
:
(define multiplier
(lambda (s)
(cond [(null? s) 1]
[(number? (car s))
(* (car s) (multiplier(cdr s)))]
[list? (car s)
(append (car s) (multiplier (cdr s)))]
[else
(multiplier (cdr s))])))
Дальнейшее изучение этой строки показывает, что код пытается добавить (car s)
к результату (multiplier (cdr s))
; тем не менее, (car s)
теперь известно, что это список, и multiplier
предполагается, что он возвращает число! Целью здесь, несомненно, было умножить результат вызова multiply
списка (car s)
вместе с результатом (multiplier (cdr s))
:
(define multiplier
(lambda (s)
(cond [(null? s) 1]
[(number? (car s))
(* (car s)
(multiplier (cdr s)))]
[(list? (car s))
(* (multiplier (car s))
(multiplier (cdr s)))]
[else
(multiplier (cdr s))])))
Неясно, зачем else
нужна ветка, если только OP не хочет иметь возможность обрабатывать такие списки, как (a (1 (2 b) (3 (c (4 5) 6) d) e)))
. Для кода, который ожидает вложенные списки чисел, это было бы хорошо:
(define multiplier-2
(lambda (s)
(cond [(null? s) 1]
[(number? (car s))
(* (car s) (multiplier (cdr s)))]
[else
(* (multiplier (car s))
(multiplier (cdr s)))])))
Обе функции теперь работают для выражения примера операции, а исправленный код операции также работает для ввода с ложными значениями:
scratch.rkt> (multiplier '((1 (2 3)) 4 5 (6)))
720
scratch.rkt> (multiplier-2 '((1 (2 3)) 4 5 (6)))
720
scratch.rkt> (multiplier '(a (1 (2 3)) 4 5 b (6) c))
720
Ответ №2:
Я думаю, что у buildin flatten
больше обработки ошибок.
(define (multiplier lst)
(apply * (filter number? (flatten lst))))
;;; TEST
(define test-lst1 (list (vector 1) '(1 (2 3) c) "w" 4 5 '(6) - * sqr))
(define test-lst2 '(1(a 2(3 b (c 4(d 5 e(6) (f)))))))
(multiplier test-lst1) ; 720
(multiplier test-lst2) ; 720