Как вы соответствуете с охранниками в ракетке?

В Scala вы можете сделать что-то вроде этого:

def times[A](item: A, number: Int): List[A] = number match {
  case n if n <= 0 => Nil // Nil = '()
  case _ => 
    // equivalent to [_ (cons item (times item (- number 1)))]
    item :: times(item, number - 1)
}

Можно ли сделать что-то подобное с помощью Racket's match форме? Я не мог найти это в документации

Для тех, кто не знаком со Scala, первый случай соответствует, если число равно или меньше 0, второй случай - это просто подстановочный знак, который соответствует всему остальному

другими словами, что бы я написал в ??? место для достижения функциональности, аналогичной описанной выше?

(define (times item number)
  (match number
    [??? '()]
    [_ (cons item (times item (- number 1)))]))

2 ответа

Решение

Ракетка-х match имеет дополнительный #:when предложение, которое позволяет вам написать это почти так же, как вы это делали в Scala:

(define (times item number)
  (match number
    [n #:when (<= n 0) '()]
    [_ (cons item (times item (- number 1)))]))

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

(define (times item number)
  (cond [(<= number 0) '()]
        [else (cons item (times item (- number 1)))]))

Хотя я бы, наверное, перевернул руки

(define (times item number)
  (cond [(positive? number) (cons item (times item (- number 1)))]
        [else '()]))

Конечно, для чего-то такого простого, что вы могли бы использовать if:

(define (times item number)
  (if (positive? number)
      (cons item (times item (- number 1)))
      '()))

Однако я предпочел использовать cond, как рекомендует руководство по стилю ракетки.

Оказывается, я не выглядел достаточно усердно, вот ответ:

(define (times item number)
  (match number
    [(? (lambda (n) (<= n 0))) '()]
    [_ (cons item (times item (- number 1)))]))

(? expr patt) определяет охранник.

Выше может быть более кратко написано как:

(define (lteq-0? n) (<= n 0))

(define (times item number)
  (match number
    [(? lteq-0?) '()]
    [_ (cons item (times item (- number 1)))]))
Другие вопросы по тегам