Список случайных номеров EOPL/Racket/Scheme между двумя номерами

Это задача:

Напишите функцию (random-number-list n lim), которая возвращает список из n случайных целых чисел в диапазоне от 0 до lim-1.

Это мой код: (я использую #lang EOPL в DrRacket)

(define (random-number-list n lim)
(letrec ((maker
            (lambda (n lim result)
              (let loop ((g lim) (result '()))
                (if (= g 0)
                    result 
                    (loop (- lim 1) (cons (random lim) result)))))))
    (maker n lim '())))

Это должно быть то, что он производит:

(random-number-list 10 20) => (1 11 4 18 3 12 17 17 8 4)

Когда я запускаю код, я получаю сообщение об ошибке "(random lim)". Что-то со случайным. Может кто знает причину? Кроме того, я на правильном пути?


person Someone    schedule 22.09.2015    source источник


Ответы (3)


Основная проблема с вашим кодом заключается в этой строке:

(loop (- lim 1) (cons (random lim) result))

Вы уменьшаете lim, но проверяете g, которое остается неизменным, что приводит к бесконечному циклу. Также в этой строке неправильно инициализировался g:

((g lim) (result '()))

Это должно решить проблемы:

(define (random-number-list n lim)
  (letrec ((maker
            (lambda (n lim result)
              (let loop ((g n) (result '()))
                (if (= g 0)
                    result
                    (loop (- g 1) (cons (random lim) result)))))))
    (maker n lim '())))

Учитывая, что вы используете Racket, знайте, что возможно более простое решение:

(define (random-number-list n lim)
  (build-list n (lambda (x) (random lim))))

В любом случае, он работает так, как ожидалось:

(random-number-list 10 20)
=> '(13 7 5 9 3 12 7 8 0 4)
person Óscar López    schedule 22.09.2015

Основная причина, по которой вы получаете сообщение об ошибке, заключается в том, что в языке #!eopl нет процедуры с именем random. Если вы видите сообщенные символы eopl, они просто не существовать. Однако он существует в #!racket.

Как указал Оскар, были некоторые логические ошибки, которые приводили к бесконечным циклам. Честная ошибка, но я также заметил, что вы используете g вместо n во внутреннем цикле. Очень часто вместо выбранной локальной переменной используется исходное имя, поэтому распространенный способ избежать этой ошибки — скрыть исходную переменную.

Также требуется только одна местная процедура. Вот мои исправления с сохранением имени let или letrec:

#!racket

;; with letrec
(define (random-number-list n lim)
  (letrec ((maker
            (lambda (n result)
              (if (zero? n)
                  result
                  (maker (- n 1)
                         (cons (random lim) result))))))
    (maker n '())))

;; with named let
(define (random-number-list2 n lim)
  (let maker ((n n) (result '()))
    (if (zero? n)
        result
        (maker (- n 1)
               (cons (random lim) result)))))

Я пропустил lim, так как оно никогда не меняется, и я использовал одно и то же имя maker, чтобы проиллюстрировать, что это то же самое, что происходит в этих двух, только синтаксис отличается. Многие реализации фактически переписывают имя let во что-то очень похожее на версию letrec.

person Sylwester    schedule 22.09.2015

Альтернатива:

(define (random-number-list n lim)
   (build-list n (λ (x) (random lim)))

Здесь build-list создает список из n элементов. Каждый элемент является результатом вызова (λ (x) (random lim)), который игнорирует x и возвращает случайное число от 0 до lim-1.

person soegaard    schedule 23.09.2015