Схема рекурсивная - PullRequest
       9

Схема рекурсивная

0 голосов
/ 07 декабря 2018

Deos кто-нибудь знает, как я могу сделать эту функцию рекурсивной, вставив функцию куда-нибудь?Мне не разрешено использовать реализованные функции для списков, кроме append, make-pair (list) и reverse.

(: split-list ((list-of %a) -> (tuple-of (list-of %a) (list-of %a))))  
(check-expect (split-list (list 1 2)) (make-tuple (list 1) (list 2)))
(check-expect (split-list (list 1 2 3 4)) (make-tuple (list 1 3) (list 2 4)))
(check-expect (split-list (list 1 2 3)) (make-tuple (list 1 3) (list 2)))
(check-expect (split-list (list 1 2 3 4 5)) (make-tuple (list 1 3 5) (list 2 4)))
(check-expect (split-list (list 1 2 3 4 5 6)) (make-tuple (list 1 3 5) (list 2 4 6)))
(define split-list
  (lambda (x)
    (match x
      (empty empty)
      ((make-pair a empty) (make-tuple a empty))
      ((make-pair a (make-pair b empty)) (make-tuple (list a) (list b)))
      ((make-pair a (make-pair b c))  (make-tuple (list a (first c)) (list b (first(rest c))))))))

Код для make-tuple:

(define-record-procedures-parametric tuple tuple-of
  make-tuple
  tuple?
  (first-tuple
   rest-tuple))

Ответы [ 4 ]

0 голосов
/ 10 декабря 2018

Вы, похоже, используете модуль deinprogramm / DMdA-vanilla.Самый простой способ - сопоставить текущее состояние списка и вызвать его снова с остальными:

(define split-list
 (lambda (x)
  (match x
   ;the result should always be a tuple
   (empty (make-tuple empty empty))
   ((list a) (make-tuple (list a) empty)) 
   ((list a b) (make-tuple (list a) (list b)))
   ;call split-list with the remaining elements, then insert the first two elements to each list in the tuple
   ((make-pair a (make-pair b c))
    ((lambda (t) 
     (make-tuple (make-pair a (first-tuple t))
                 (make-pair b (rest-tuple t))))
     (split-list c))))))
0 голосов
/ 07 декабря 2018

Вот как это можно исправить, используя match и с именем let, обозначенные ниже как loop.

(define (split xs)
  (let loop ((xs xs)       ;; the list, initialized with our input
             (l empty)     ;; "left" accumulator, initialized with an empty list
             (r empty))    ;; "right" accumulator, initialized with an empty list
    (match xs
      ((list a b rest ...) ;; at least two elements
       (loop rest
             (cons a l)
             (cons b r)))
      ((cons a empty)      ;; one element
       (loop empty
             (cons a l)
             r))
      (else                ;; zero elements
       (list (reverse l)
             (reverse r))))))

вышемы используем loop для построения влево и вправо списков, затем мы используем reverse для возврата окончательного ответа.Мы можем избежать перевернуть ответ, если построим ответ в обратном порядке!Используемая здесь техника называется стиль передачи продолжения .

(define (split xs (then list))
  (match xs
    ((list a b rest ...)             ;; at least two elements
     (split rest
            (λ (l r)
              (then (cons a l)
                    (cons b r)))))
    ((cons a empty)                  ;; only one element
     (then (list a) empty))
    (else                            ;; zero elements
     (then empty empty))))

Обе реализации выполняют в соответствии со спецификацией.

(split '())
;; => '(() ())

(split '(1)) 
;; => '((1) ())

(split '(1 2 3 4 5 6 7))
;; => '((1 3 5 7) (2 4 6))

Группировка результата в list являетсяинтуитивно понятный по умолчанию, но, вероятно, вы все равно планируете что-то делать с отдельными частями

(define my-list '(1 2 3 4 5 6 7))

(let* ((result (split my-list))  ;; split the list into parts
       (l (car result))          ;; get the "left" part
       (r (cadr result)))        ;; get the "right" part
  (printf "odds: ~a, evens: ~a~n" l r))
;; odds: (1 3 5 7), evens: (2 4 6)

Выше, стиль передачи продолжения дает нам уникальный контроль над возвращаемым результатом.Продолжение настраивается на сайте вызова с использованием второго параметра.

(split '(1 2 3 4 5 6 7) list)  ;; same as default
;; '((1 3 5 7) (2 4 6))

(split '(1 2 3 4 5 6 7) cons)
;; '((1 3 5 7) 2 4 6)

(split '(1 2 3 4 5 6 7)
       (λ (l r)
         (printf "odds: ~a, evens: ~a~n" l r)))
;; odds: (1 3 5 7), evens: (2 4 6)

(split '(1 2 3 4 5 6 7)
       (curry printf "odds: ~a, evens: ~a~n"))
;; odds: (1 3 5 7), evens: (2 4 6)

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

  1. создание списка вывода без необходимости его реверсирования
  2. возврат нескольких значений
0 голосов
/ 09 декабря 2018

split является своего рода функцией de-interleave.Во многих других языках split называет функции, которые создают подсписки / подпоследовательности списка / последовательности, которые сохраняют фактический порядок.Вот почему я не люблю называть эту функцию split, потому что она каким-то образом меняет порядок элементов.

Решение с помощью Tail-Call-Rescursive

(define de-interleave (l (acc '(() ())))
  (cond ((null? l) (map reverse acc)) ; reverse each inner list
        ((= (length l) 1)             
         (de-interleave '() (list (cons (first l) (first acc))
                                  (second acc))))
        (else                         
         (de-interleave (cddr l) (list (cons (first l) (first acc)) 
                                       (cons (second l) (second acc)))))))
0 голосов
/ 07 декабря 2018

У меня нет доступа к определениям make-pair и make-tuple, которые вы используете.Я могу думать о рекурсивном алгоритме в терминах списков схем, должно быть легко адаптировать его к вашим требованиям, просто используйте make-tuple вместо list, make-pair вместо cons и внесите необходимые корректировки:

(define (split lst l1 l2)
  (cond ((empty? lst) ; end of list with even number of elements
         (list (reverse l1) (reverse l2))) ; return solution
        ((empty? (rest lst)) ; end of list with odd number of elements
         (list (reverse (cons (first lst) l1)) (reverse l2))) ; return solution
        (else ; advance two elements at a time, build two separate lists
         (split (rest (rest lst)) (cons (first lst) l1) (cons (second lst) l2)))))

(define (split-list lst)
  ; call helper procedure with initial values
  (split lst '() '()))

Например:

(split-list '(1 2))
=> '((1) (2))
(split-list '(1 2 3 4))
=> '((1 3) (2 4))
(split-list '(1 2 3))
=> '((1 3) (2))
(split-list '(1 2 3 4 5))
=> '((1 3 5) (2 4))
(split-list '(1 2 3 4 5 6))
=> '((1 3 5) (2 4 6))
...