Scheme 将列表排序为子列表

Scheme 将列表排序为子列表,scheme,racket,Scheme,Racket,我试图创建一个程序,对列表进行排序,然后将列表的每个部分分组到单独的列表中,并将其输出到列表列表中。这里有一个检查应该更清楚: > (sort-lists > '()) empty > (sort-lists < '(1 2 3)) (list (list 1 2 3)) > (sort-lists >= '(2 2 2 2)) (list (list 2 2 2 2)) > (sort-lists < '(5 4 3 2 1)) (list

我试图创建一个程序,对列表进行排序,然后将列表的每个部分分组到单独的列表中,并将其输出到列表列表中。这里有一个检查应该更清楚:

> (sort-lists > '())
empty

> (sort-lists < '(1 2 3))
(list (list 1 2 3))

> (sort-lists >= '(2 2 2 2))
(list (list 2 2 2 2))

> (sort-lists < '(5 4 3 2 1))
(list (list 5) (list 4) (list 3) (list 2) (list 1))

> (sort-lists < '(1 2 3 4 2 3 4 5 6 1 2 9 8 7))
(list
 (list 1 2 3 4)
 (list 2 3 4 5 6)
 (list 1 2 9)
 (list 8)
 (list 7))
我对(first(restls))部分有一个问题,因为如果没有first of rest,那么它会给出一个错误,rest的其余部分也是如此

此外,这必须是一个单通函数,在ISL+中没有任何帮助程序。任何帮助都会很好


是否有一种方法可以使用local将递归子问题的解决方案合并到ans变量,然后完成答案。所以对于
(sort list<'(1234245612987))
,您可以将ans定义为运行
(sort list<'(2344434561297))
,也就是
((234)(23456)(1298)(7))。
我不会将其称为某种类型的分区。您试图收集已根据谓词排序的最长连续元素序列。我知道你说过你必须把这些都打包成一个函数,但是首先把它写成单独的函数,然后把它们合并成一个函数可能会容易得多

在解决这个问题时,将其分解为子任务可能会有所帮助。首先,在最高级别,当列表出现时,有一些升序元素的初始前缀,然后是其后的其余元素。结果应该是第一个前缀的列表,然后是处理其余元素的结果。这给了我们一个这样的结构:

(define (slice predicate lst)
  (if (empty? lst)
      ;; If lst is empty, then there no contiguous 
      ;; subsequences within it, so we return '() 
      ;; immediately.
      '()
      ;; Otherwise, there are elements in lst, and we 
      ;; know that there is definitely a prefix and
      ;; a tail, although the tail may be empty. Then
      ;; the result is a list containing the prefix,
      ;; and whatever the sliced rest of the list is.
      (let* ((prefix/tail (ordered-prefix predicate lst))
             (prefix (first prefix/tail))
             (tail (second prefix/tail)))
        (list* prefix (slice predicate tail)))))
我希望该功能的逻辑相对清晰。唯一可能有点不寻常的位是执行顺序绑定的let*,以及与**cons相同的list**。还有一个对函数的引用,ordered prefix,我们还没有定义它。它的任务是返回两个值的列表;第一个是列表的有序前缀,第二个是该前缀之后的列表尾部。现在我们只需要编写该函数:

(define (ordered-prefix predicate lst)
  (cond
    ;; If the list is empty, then there's no prefix,
    ;; and the tail is empty too.
    ((empty? lst)
     '(() ()))
    ;; If the list has only one element (its `rest` is
    ;; empty, then the prefix is just that element, and 
    ;; the tail is empty.
    ((empty? (rest lst))
     (list (list (first lst)) '()))
    ;; Otherwise, there are at least two elements, and the
    ;; list looks like (x y zs...).
    (else 
     (let ((x (first lst))
           (y (second lst))
           (zs (rest (rest lst))))
       (cond
         ;; If x is not less than y, then the prefix is (x),
         ;; and the tail is (y zs...).
         ((not (predicate x y))
          (list (list x) (list* y zs)))
         ;; If x is less than y, then x is in the prefix, and the 
         ;; rest of the prefix is the prefix of (y zs...).  
         (else 
          (let* ((prefix/tail (ordered-prefix predicate (list* y zs)))
                 (prefix (first prefix/tail))
                 (tail (second prefix/tail)))
            (list (list* x prefix) tail))))))))
现在,这足以使切片工作:

(slice < '())                ;=> ()
(slice < '(1 2 3 4 2 3 4 5)) ;=> ((1 2 3 4) (2 3 4 5))

但是,这对排序前缀不起作用,因为排序前缀是递归的;它需要能够指代自己。不过,您可以使用letrec实现这一点,它允许函数引用自身。例如:

(define (repeat-n-reverse lst n)
  (letrec ((repeat-n (lambda (x n)
                       (if (= n 0) 
                           '()
                           (list* x (repeat-n x (- n 1)))))))
    (repeat-n (reverse lst) n)))

好了,现在我们准备好把它们放在一起了。(由于有序前缀现在是在切片中定义的,因此它已经可以访问谓词,我们可以将其从参数列表中删除,但仍然使用它。)

这也是相对有效的。它不会分配任何不必要的数据,除了为了清晰起见我使用了(list*y zs)的地方,那里的值与(rest lst)的值相同。你可能应该改变这一点,但为了清楚起见,我想保持原样


唯一的性能考虑是,这不是尾部递归,因此需要使用更多的堆栈空间。为了避免这种情况,您需要将递归转换为一种以相反的方式构建列表的形式,然后在返回列表时将其反转。这就是我在原著中所做的(你仍然可以查看编辑历史记录),但对于看起来像是学术练习的内容来说,这可能有些过头了。

你想将列表分解为最长的升序数字序列。并在ISL+中一次性完成

这在逻辑编程伪代码(好的,Prolog)中实现:

运行([],[[]])。
运行([A],[A]])。
运行([A,B | C],R):-
(A>B->runs([B | C],S),R=[A]| S]
;true->runs([B|C],[D|S]),R=[A|D]| S])。
在类似伪码的方案中也是如此(好吧,全拍):

(定义(运行xs)
(匹配xs)
((列表)“(()))
((名单A)(名单A)))
((列表A B C…)
(续)
((>AB)
(让([S(runs(cons B C))]))
(反对(附表A))
(其他
(让([dus(runs(cons B C))]))
(让([D(car D_s)]
[S(cdr d_S)])
(反对党(反对党A/D)S()()())))
剩下要做的就是将其融入ISL+语言中。我不知道+代表什么,但在“中间学生使用lambda”语言中肯定允许使用
lambda
结构。这使我们可以模拟嵌套的
let
s的分阶段分配

          ( (lambda (d_s)
               ( (lambda (D S)
                     (cons (cons A D) S))
                 (car d_s)
                 (cdr d_s)))
            (runs (cons B C)))

我已经看过了,但大部分都没有意义。我们还没有完成letrec、loop或let。我查找了letrec和let,它们看起来像是local和lambda函数,但是在letrec和“^”前缀中有一个letrec,这没有多大意义。有没有一种方法过于简单的语言?@Ryan实际上,我清理了一些代码
letrec
与let类似,只是它绑定的变量在其他绑定的范围内。例如,您可以执行
(letrec((p(lambda(n)(pn)))(p10))
将是一个无限循环,因为
p
绑定到调用
p
的函数(它本身)<代码>循环没有什么特别之处;它只是绑定到函数的另一个变量。我只是使用了名称
loop
,因为它是一个递归函数,本质上执行循环。变量上的
^
也没有任何作用;我只是用它来表示needed@Ryan在返回之前要反转。在许多列表处理练习中,以相反的顺序构建结果,然后在返回结果时将其反转更容易。所以在从(1231)构建(1233)的过程中,我们将逐步构建前缀/尾部组合()/(1231),然后(1)/(231),然后(211)/(311),然后(321)/(1),然后我们反转前缀以返回(1233)/(1)。好的。我还是不知道
(repeat-reverse '(1 2 3)) ;=> ((3 2 1) (3 2 1))
(define (repeat-n-reverse lst n)
  (letrec ((repeat-n (lambda (x n)
                       (if (= n 0) 
                           '()
                           (list* x (repeat-n x (- n 1)))))))
    (repeat-n (reverse lst) n)))
(repeat-n-reverse '(1 2 3) 3)     ;=> ((3 2 1) (3 2 1) (3 2 1))
(repeat-n-reverse '(x y) 2)       ;=> ((y x) (y x))
(repeat-n-reverse '(a b c d e) 0) ;=> ()
(define (slice predicate lst)
  (letrec ((ordered-prefix
            (lambda (lst)
              (cond
                ((empty? lst)
                 '(() ()))
                ((empty? (rest lst))
                 (list (list (first lst)) '()))
                (else 
                 (let ((x (first lst))
                       (y (second lst))
                       (zs (rest (rest lst))))
                   (cond
                     ((not (predicate x y))
                      (list (list x) (list* y zs)))
                     (else 
                      (let* ((prefix/tail (ordered-prefix (list* y zs)))
                             (prefix (first prefix/tail))
                             (tail (second prefix/tail)))
                        (list (list* x prefix) tail))))))))))
    (if (empty? lst)
        '()
        (let* ((prefix/tail (ordered-prefix lst))
               (prefix (first prefix/tail))
               (tail (second prefix/tail)))
          (list* prefix (slice predicate tail))))))
          ( (lambda (d_s)
               ( (lambda (D S)
                     (cons (cons A D) S))
                 (car d_s)
                 (cdr d_s)))
            (runs (cons B C)))