以列表形式保留子列表

时间:2017-02-27 03:22:55

标签: scheme lisp sicp

我正在做家庭作业,以遍历DAG,找到最短的路线。在一些SO答案的帮助下,我有相当多的部分。话虽这么说,我无法获得一个函数来返回一个子列表列表,就像我需要进一步处理数据一样。数据文件具有表单(node1 node2 weight)

中的子列表列表
(define (children? node)
  (define list '(1))
  (map (lambda (x)
         (cond
           ((equal? (car x) node)
           (if (equal? list '(1))
               (set-car! list x)
           (append! list x)))))
   data)
(if (equal? list '(1))
  #f
  list))

(define (append! lst . lsts)
  (if (not (null? lsts))
  (if (null? (cdr lst))
      (begin
        (set-cdr! lst (car lsts))
        (apply append! (car lsts) (cdr lsts)))
      (apply append! (cdr lst) lsts))))

当我跑步(儿童?'b3)时,我得到的结果如下:

((b3 b5 57)b3 b4 81 b3 b10 55 b3 b14 61 b3 b13 66)

它实际上应该是什么样的

((b3 b5 57)(b3 b4 81)(b3 b10 55)(b3 b14 61)(b3 b13 66))

任何人都可以对我的问题有所了解吗?

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

修复缩进,您的代码变为

(define (children? node)
  (define list '(1))

使用头部哨兵技巧。不错嘛...)。但由于它的目的是手术改变,它应该是新鲜的,而不是引用的数据:

  (define list (list 1))
等等,什么?两个list s?这不是Common Lisp,是吗? Scheme是一个Lisp-1,而不是Lisp-2;函数和值的名称位于同一名称空间中;所以;别'吨

  (define lst (list 1))

  (map (lambda (x)
         (cond
           ((equal? (car x) node)
              (if (equal? list '(1))
                  (set-car! list x)
                  (append! list x)))))

连续两个条件只是一个and,但更重要的是,头部哨兵技巧意味着你将(cdr lst)返回真实结果,因此不需要改变其头部的内容。然后代码简化了,这是首先使用头部哨兵的全部目的:

  (map (lambda (x)
         (if (equal? (car x) node)
             (append! lst x)))      ; changed the name

没有替代条款?一般来说,不赞成,但在这里你做了副作用的地图,所以,只要你使用map的结果,你就是&#39 ;好的。更容易就是总是处理备用条款作为习惯和良好风格的问题,如

  (map (lambda (x)
         (if (equal? (car x) node)
             (append! lst x)   ; append two lists together... (see below)
             #f))
       data)

data?那是什么?它应该作为children?的另一个形式参数添加。

  (if (equal? lst '(1))

equal??为什么?要查看我们是否对其进行了更改,只需

即可
  (if (null (cdr lst))

最少行动原则......

      #f
      (cdr lst)))    ; cdr carries the true payload

(基本上,

(define (children? node data)
    (let ((res (filter (lambda (x) (equal? (car x) node)) 
                       data)))
      (if (not (null? res))
         res
         #f)))

)。好。是吗?嗯,这取决于以下工作正常。

(define (append! lst . lsts)
  (if (not (null? lsts))
      (if (null? (cdr lst))
        (begin
          (set-cdr! lst (car lsts))
          (apply append! (car lsts) (cdr lsts)))

附加列表,因此(append! (list 1) (list 2))将返回与(list 1 2)(append! (list 1) (list 2 3))相同的结果,与(list 1 2 3)相同。要在列表的末尾添加项目(如2),我们必须先将其放入另一个列表中。因此,如果我们添加的项目本身就是一个列表,例如'(2 3),我们希望得到'(1 (2 3))。为此,必须在附加之前将项目括在列表中。所以必须修改你的功能才能做到这一点。

      (apply append! (cdr lst) lsts))))

在这里,您扫描您的(成长)结果列表,再次找到它的最后一个单元格,再次再次。您可以通过自己维护最后一个单元格指针并直接使用它来解决这个问题。什么"指针"?它lstcdr每次append!有什么东西;所以你可以直接你(set-cdr! lst (list item))做你的事。你当然不能使用lst变量(为什么?)。

答案 1 :(得分:1)

通过应用Algol编程经验(如C或Java)的知识,您的代码看起来正在学习Scheme。在Scheme中你应该尝试在没有变异的情况下进行编程,除非你有充分的理由这样做。保持大部分程序纯正意味着它更容易测试。

命名约定很重要,程序结束了吗?是一个谓词,因此它应该返回两个值#t#f中的一个,就像isString应该在Algol语言中返回true / false一样。

 
;; graph constructor/accessors not not use car, cadr, etc
;; later you can change it to boxes
(define (make-graph from to weight)
  (list from to weight))
(define graph-from car)
(define graph-to cadr)
(define graph-wight cddr)

;; gets the graphs that has node as starting point
(define (graphs-from node graphs)
  ; match? returns #t if graph starting point is the same as node
  ; since it's symbols we use eq?
  (define (match? graph)
    (eq? node (graph-from graph)))

  ; filters data by starting point
  ; this is the tail expression and thus the result of this procedure
  (filter match? graphs))

(define data (list (make-graph 'x 'y 20)
                   (make-graph 'y 'x 30)
                   (make-graph 'w 'e 20)
                   (make-graph 'x 'e 13)))

(graphs-from 'x data)
; ==> ((x y 20) (x e 13))

(graphs-from 'a data)
; ==> ()