Преобразование списка цифр в число

Мне было интересно, есть ли способ взять список чисел (цифр) и обрезать числа вместе, чтобы получить одно большое число (не сложение) в схеме. Например, я хотел бы

(foo '(1 2 3 4))
;=> 1234

Есть ли в Scheme встроенная функция для этого?


person John Friedrich    schedule 23.10.2013    source источник
comment
Нет, но это довольно легко реализовать с помощью reduce   -  person Joshua Taylor    schedule 24.10.2013


Ответы (1)


В семейство Scheme входит несколько языков, а также несколько версий Scheme. Если вы используете один, например, Racket, который включает в себя левую ассоциативную складку (часто называемую foldl, fold или reduce, хотя есть и другие варианты), это довольно просто реализовать с точки зрения сгиба. Складки более подробно описаны в следующих вопросах и ответах:

  • Поиск максимального расстояния между двумя точками в списке (схема) Этот вопрос включает описание того, как fold можно рассматривать как итеративный конструкция (а в схеме, которая требует оптимизации хвостовых вызовов, компилируется в итеративный код), а также включает реализацию foldl для схем, в которых ее нет.
  • Сведение списка списков Этот вопрос касается несколько необычного сгиба и того, как его (или стандартный сгиб) можно использовать чтобы сгладить список.
  • структуры и списки схем В этом вопросе есть пример того, как вы можете настроить функцию, которую вы передаете в складку, чтобы добиться немного другого поведение. (Я также включил самоуверенный (но правдивый ;), уверяю вас) комментарий о том, что Common Lisp reduce предоставляет несколько более удобный интерфейс, чем тот, который предоставляется в некоторых библиотеках Scheme.

Вот как выглядит код с точки зрения foldl:

(define (list->num digits)
  (foldl (lambda (digit n)
           (+ (* 10 n) digit))
         0
         digits))
> (list->num '(1 2 3 4))
1234 

Если в вашем языке нет этого, foldl довольно легко написать (например, мой ответ на вопрос из приведенных выше вопросов включает реализацию) и используйте предыдущий код, или вы можете написать всю функцию (используя тот же подход) самостоятельно:

(define (list->num-helper digits number-so-far)
  (if (null? digits)
      number-so-far
      (list->num-helper (cdr digits)
                        (+ (* 10 number-so-far)
                           (car digits)))))

(define (list->num digits)
  (list->num-helper digits 0))

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

(define (list->num digits)
  (let l->n ((digits digits)
             (number 0))
    (if (null? digits)
        number
        (l->n (cdr digits)
              (+ (* 10 number)
                 (car digits))))))
person Joshua Taylor    schedule 23.10.2013
comment
Если бы я не использовал здесь циклы (я не дошел до этой части в своей книге), я бы просто повторял свою функцию, пока список не станет нулевым? - person John Friedrich; 24.10.2013
comment
Здесь нет смысла использовать циклы. Я просто использовал конструкцию с именем let и случайно использовал цикл имени. Я также покажу версию, в которой используется вспомогательная функция. - person Joshua Taylor; 24.10.2013
comment
В R6RS у вас есть fold-left в rnrs lists библиотеке - person Sylwester; 24.10.2013
comment
На случай, если кто-нибудь прочитает мой комментарий выше, я изменил loop на l->n, чтобы избежать путаницы. - person Joshua Taylor; 24.10.2013