【问题标题】:Scheme looping through an expression that contains lists方案循环遍历包含列表的表达式
【发布时间】:2017-12-27 01:28:42
【问题描述】:

我在 Scheme 中做一个问题,即创建一个函数,该函数接受一个对象和一个表达式,例如 (foo 'x '(x 10 x x 4)) 并且必须返回给定对象后面的所有对象,所以上面的函数调用将返回 @ 987654322@。但是,表达式也可以包含列表,例如 (foo 'y '(y (3 y 5 y y 8 9) (10 y 12 13 y 15 y) 17)) 应该返回 ((3 y 5 y y 8 9) 5 y 8 12 15)。当它们包含列表时我遇到了麻烦。到目前为止,这是我的代码。

(define (foo target expression)
  (cond [(null? expression)]
        [(list? (first expression)) (foo target (first expression))]
        [(eqv? (first expression) target) (cons (first (rest expression)) (foo target (rest expression)))]
        [(not (eqv? (first expression) target)) (foo target (rest expression))]))

所以当表达式包含一个列表时,我试图递归调用该列表上的函数,但是,我不知道如何返回原始表达式以继续搜索。

所以当我调用(foo 'y '(y (3 y 5 y y 8 9) (10 y 12 13 y 15 y) 17)) 时,我得到了((3 y 5 y y 8 9) 5 y 8 . #t),所以它成功循环通过第一个列表,但之后它停止并且没有到达表达式中的第二个列表

另外,我遇​​到的另一个问题是结果末尾的布尔值,我知道这是因为 cond [(null? expression)] 行,我添加了这个是因为当它到达末尾时出现错误表达式,我该如何解决这个问题?

【问题讨论】:

    标签: scheme


    【解决方案1】:

    请注意,只有当您使用空列表 '() 终止它时,(cons x (cons y ... 才会成为正确的列表。因此(cons x (cons y ... empty)) 是正确的,相当于(list x y ...),而不是你所拥有的:(cons x (cons y ... #t))。您可以通过将 '() 设置为基本案例的结果来解决此问题。

    但是当输入列表的元素少于 2 个时,您还需要第二个基本情况来测试。这是因为您的函数稍后会尝试以(first (rest expression)) 访问第二个元素。因此,为了确保这是有效的,您需要确保 expression 包含至少 2 个元素。这可以在您的条件下以... (null? (rest expression)) ... 的形式完成。

    另一方面,由于这一行,您的函数只迭代它遇到的第一个列表元素:

    [(list? (first expression)) (foo target (first expression))]
    

    在这种情况下,您只处理(first expression),但您需要同时处理(first expression)(rest expression)。由于您正在重建一个列表,因此您可以将 cons 用作:

    (cons (foo target (first expression))
          (foo target (rest expression)))
    

    但这会重新创建原始列表的深度。从您想要的输出示例中,您似乎希望将结果展平,因此更好的选择是将append它们为:

    (append (foo target (first expression))
            (foo target (rest expression)))
    

    考虑以下重写:

    (define (foo obj expr)
      (cond
        [(null? expr) #f]
        [(null? (rest expr)) '()]
        [(pair? (first expr))
         (append (foo obj (first expr))
                 (foo obj (rest expr)))]
        [(equal? obj (first expr))
         (cons (second expr)
               (foo obj (rest expr)))]
        [else
         (foo obj (rest expr))]))
    

    那么你将拥有:

    (foo 'x '(x 10 x x 4))
    => '(10 x 4)
    (foo 'y '(y (3 y 5 y y 8 9) (10 y 12 13 y 15 y) 17))
    => '((3 y 5 y y 8 9) 5 y 8 12 15)
    

    但你也会有:

    (foo 'x '())
    => #f
    (foo 'x '(x))
    => '()
    

    【讨论】:

    • 谢谢你,还有一件事,问题中给出的例子之一是(foo 'z 'z) => (),我该如何添加这个?它目前给出一个错误说rest: contract violation expected: (and/c list? (not/c empty?)) given: z
    • 我已经添加了[(not (list? expr)) '()],它似乎有效,这是正确的吗?
    • 你是对的。这样,只要输入表达式不是列表,您就会输出空列表。只需确保订购它,以便将其作为您的第一个基本案例进行测试。
    猜你喜欢
    • 2014-05-11
    • 1970-01-01
    • 2016-05-10
    • 2013-06-22
    • 1970-01-01
    • 2014-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多