Схема / Ракетка - Подсчитайте все положительные значения в списке - PullRequest
1 голос
/ 20 октября 2019

У меня нет большого опыта работы со схемой / ракеткой, но я пытаюсь создать функцию, которая вычисляет, сколько положительных значений в списке. Пока у меня есть это:

(define num_pos 0)
(define num_neg 0)
(define (numpos lst)
 (cond
  ((null? lst) 0)
  ((>= (car lst) 0) (+ num_pos 1) (numpos (cdr lst)))
  (else (+ num_neg 1) (numpos (cdr lst)))
  )
)

Но когда я запускаю его в DrRacket и проверяю его, lst всегда пуст, поэтому, если я вызываю (numpos '(1 -1 2)), он возвращает 0 нанулевая проверка, но если я удаляю нулевую проверку, она падает (car lst), говоря, что она ожидает пару, но получает '(). Я потратил немного на это без удачи. Есть идеи?

Ответы [ 2 ]

3 голосов
/ 20 октября 2019

(+ num_pos 1) не изменяет значение num_pos. Попробуйте заменить его на (set! num_pos (+ num_pos 1)) и сделать то же самое для num_neg.

. После вызова (numpos '(1 -1 2)) значение num_pos становится равным 2.

EDIT Я полностью согласен с комментарием Оскара, и он уже добавил лучший ответ. Вот альтернативный пример с дополнительной поддержкой num_neg:

(define (numpos lst num_pos num_neg)
 (cond
  ((null? lst)
   (list num_pos num_neg))
  ((>= (car lst) 0)
   (numpos (cdr lst) (+ num_pos 1) num_neg))
  (else
   (numpos (cdr lst) num_pos      (+ num_neg 1)))))

Если вы позвоните (numpos '(1 -1 2) 0 0), он вернет список, содержащий количество положительных и отрицательных значений, таких как (2 1).

Обратите внимание, что для новой версии требуются дополнительные 2 аргумента, каждый из которых должен быть равен 0. Эти параметры работают как num_pos и num_neg в исходном коде. И это хвостовая рекурсия .

С помощью хвостовой рекурсии вы можете легко удалить побочные эффекты (доступ к глобальной переменной).

Если вам не нравятся эти дополнительные аргументы,Вы можете переписать с внутренней define, как показано ниже:

(define (numpos lst)
  (define (iter lst num_pos num_neg)
    (cond
     ((null? lst)
      (list num_pos num_neg))
     ((>= (car lst) 0)
      (iter (cdr lst) (+ num_pos 1) num_neg))
     (else
      (iter (cdr lst) num_pos      (+ num_neg 1)))))
  (iter lst 0 0))
2 голосов
/ 20 октября 2019

В Схеме мы пытаемся написать процедуры, используя парадигму функционального программирования . В вашем примере определение счетчика за пределами не является хорошей идеей, чтобы изменить его значение, вам нужно мутировать внутри, используя инструкцию set!, и мы должныизбегайте именно этого.

Обычное решение (если мы собираемся решить это «вручную») состоит в том, чтобы рекурсивно обходить список и увеличивать значение при каждом рекурсивном вызове, обратите внимание, что мы не делаемдаже нужно увеличивать переменные внутри процедуры, например:

(define (numpos lst)
  (cond
    ((null? lst) 0)
    ((>= (car lst) 0) (+ 1 (numpos (cdr lst))))
    (else (numpos (cdr lst)))))

Ключ к пониманию того, как это работает, находится здесь:

(+ 1 (numpos (cdr lst)))

Мы добавляем единицу к результату рекурсиии мы продолжаем делать это для каждого положительного числа, пока не достигнем конца списка и не добавим ноль в конце.

В своем коде вы написали следующее: (+ num_pos 1), но это выражениене изменение значения num_pos, это просто добавление единицы к нулю, но никогда сохранение результата сложения!

Теперь мы можем определить переменные с помощьюправильные значения, шЧтобы вычислить num_pos только с помощью процедуры, можно легко определить значение num_neg:

(define num_pos (numpos lst))
(define num_neg (- (length lst) num_pos))

Существует много способов решения этой проблемы. Ознакомившись с рекурсивными процедурами, вы обнаружите, что существует множество встроенных процедур, которые позволяют быстро найти решение распространенных проблем. На самом деле, идиоматический способ ответить на ваш вопрос - использовать count:

(define (numpos lst)
  (count (lambda (n) (>= n 0))
         lst))
...