Функция Scheme для обращения элементов списка 2-list - PullRequest
1 голос
/ 18 февраля 2011

Это упражнение из EOPL.Процедура (invert lst) принимает lst, который является списком из 2 списков, и возвращает список с каждым обращенным к нему 2 списком.

(define invert
  (lambda (lst)
    (cond((null? lst )
         '())
       ((= 2 (rtn-len (car lst)))
        ( cons(swap-elem (car lst))
               (invert (cdr lst))))
       ("List is not a 2-List"))))

;; Auxiliry Procedure swap-elements of 2 element list

(define swap-elem
  (lambda (lst)
    (cons (car (cdr lst))
          (car lst))))

;; returns lengh of the list by calling
(define rtn-len
  (lambda (lst)
    (calc-len lst 0)))        

;; calculate length of the list
(define calc-len
  (lambda (lst n)
    (if (null? lst)
        n
        (calc-len (cdr lst) (+ n 1)))))

Это работает, однако выглядит очень многословно.Может ли это быть сокращено или написано более элегантно?Как я могу остановить обработку в каком-либо отдельном элементе не из 2-х списков?В данный момент выполнение переходит к следующему члену и заменяет текущего члена на «Список не является 2-списком», если текущий член не является 2-списком.

Ответы [ 4 ]

1 голос
/ 18 февраля 2011

Если вы хотите досрочно завершить работу, попробуйте позвонить / cc.

(call-with-current-continuation
  (lambda (exit)
    (for-each (lambda (x)
                (if (negative? x)
                    (exit x)))
              '(54 0 37 -3 245 19))
    #t))  
                          ===>  -3

(взято из http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_idx_566)

Что делает call-with-current-continuation (или call/cc, для краткости), это передает точку, в которой функция была вызвана, в функцию, которая обеспечивает способ иметь что-то аналогичное оператору возврата в C. Это также может гораздо больше, поскольку вы можете хранить продолжения или передавать более одного в функцию, причем другое вызывается для успеха и для неудачи.

1 голос
/ 19 февраля 2011

Язык EOPL предоставляет процедуру eopl:error для досрочного выхода с сообщением об ошибке.Он представлен на странице 15 книги (3-е изд.).

Язык EOPL также включает процедуру map из стандартной схемы.Хотя это не может быть использовано в книге, вы все равно можете использовать его, чтобы получить гораздо более короткое решение, чем решение с явной рекурсией.Также вы можете использовать стандартную процедуру Схемы length.

#lang eopl

(define invert
  (lambda (lst)
    (map swap-elem lst)))

;; Auxiliary Procedure swap-elements of 2 element list

(define swap-elem
  (lambda (lst)
    (if (= 2 (length lst))
        (list (cadr lst)
              (car lst))
        (eopl:error 'swap-elem
                    "List ~s is not a 2-List~%" lst))))
1 голос
/ 18 февраля 2011

Так что, похоже, ваша версия invert на самом деле возвращает список другой топологии. Если вы выполните (invert ...) для '((1 2) (3 4)), вы получите обратно '((2 . 1) (4 . 3)), который является списком выражений, а не списков.

Я написал версию инвертирования, которая поддерживает топологию списка, но она не является хвостовой рекурсией, поэтому в итоге она будет поддерживать стек вызовов во время его повторения.

(define (invert lst)
  (if (null? lst)
      lst
      (cons (list (cadar lst) (caar lst))
            (invert (cdr lst)))))

Если вы хотите версию, которая имитирует ваше поведение инвертирования, замените list на cons в секундах до последней строки.

0 голосов
/ 07 апреля 2018

Обратный список, содержащий любое число или порядок вложенных списков внутри.

(define (reverse! lst)
  (if (null? lst) lst
    (if (list? (car lst))
      (append (reverse! (cdr lst)) (cons (reverse! (car lst)) '()))
      (append (reverse! (cdr lst)) (list (car lst))))))
...