Как реализовать необязательные аргументы в CHICKEN? - PullRequest
4 голосов
/ 11 июня 2019

Я новичок в курице и Схеме.В своем стремлении понять хвостовую рекурсию я написал:

(define (recsum x) (recsum-tail x 0))
(define (recsum-tail x accum)
  (if (= x 0)
      accum
      (recsum-tail (- x 1) (+ x accum))))

Это делает то, что я ожидаю.Тем не менее, это кажется немного повторяющимся;необязательный аргумент должен сделать это аккуратнее.Поэтому я попытался:

(define (recsum x . y)
  (let ((accum (car y)))
    (if (= x 0)
        accum
        (recsum (- x 1) (+ x accum)))))

Однако, в CHICKEN (и, возможно, в других реализациях схемы), car нельзя использовать против ():

Error: (car) bad argument type: ()

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

Ответы [ 2 ]

3 голосов
/ 12 июня 2019

Цыпленок имеет необязательные аргументы.Вы можете сделать это следующим образом:

(define (sum n #!optional (acc 0))
  (if (= n 0)
      acc
      (sum (- n 1) (+ acc n))))

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

;;chicken-install srfi-89 # install the egg
(use srfi-89) ; imports the egg
(define (sum n (acc 0))
  (if (= n 0)
      acc
      (sum (- n 1) (+ acc n))))

Также работает ваша идея использования остальных аргументов.Однако имейте в виду, что процедура затем будет строить pair в куче для каждой итерации:

(define (sum n . acc-lst)
  (define acc 
    (if (null? acc-lst) 
        0 
        (car acc-lst)))

  (if (= n 0)
      acc
      (sum (- n 1) (+ acc n))))

Вся эта утечка внутренней информации.Иногда в публичный контракт входит необязательный параметр, но в этом случае следует избегать написания еще нескольких строк.Обычно вы не хотите, чтобы кто-то передавал второй аргумент, и вы должны держать внутреннюю конфиденциальность.Лучшим способом было бы использовать имя let и сохранить публичный контракт как есть.

(define (sum n)
  (let loop ((n n) (acc 0))
    (if (= n 0)
        acc
        (loop (- n 1) (+ acc n))))
3 голосов
/ 12 июня 2019

Я думаю, что вы ищете с именем let, а не для необязательных аргументов процедуры.Это простой способ определить вспомогательную процедуру с (возможно) дополнительными параметрами, которые вы можете инициализировать при необходимости:

(define (recsum x)
  (let recsum-tail ((x x) (accum 0))
    (if (= x 0)
        accum
        (recsum-tail (- x 1) (+ x accum)))))

Конечно, мы также можем реализовать ее с помощью varargs - но я не думаю, что это выглядиткак элегантно:

(define (recsum x . y)
  (let ((accum (if (null? y) 0 (car y))))
    (if (= x 0)
        accum
        (recsum (- x 1) (+ x accum)))))

В любом случае, все работает как положено:

(recsum 10)
=> 55
...