【问题标题】:Is it possible to create a circular data structure in Scheme without mutation?是否可以在 Scheme 中创建一个没有变异的循环数据结构?
【发布时间】:2018-04-01 20:20:08
【问题描述】:

我可以像这样在 Scheme 中创建一个循环数据结构:

(define my-pair (cons 1 1))
(set-car! my-pair my-pair)

是否可以在不使用突变的情况下在 Scheme 中创建循环数据结构? (我正在准备关于引用计数限制的讲座。)

【问题讨论】:

  • 我猜这是不可能的,因为 Scheme 是急切的,但也许你可以用 Y 运算符做一些时髦的事情。
  • 所以答案似乎是:“不,除非你改变cons的意思”。

标签: functional-programming scheme reference-counting


【解决方案1】:

你可以用闭包创建一个惰性列表:

; The infinite list (1 1 1 ...
(define ones
  (letrec ((x (cons 1 (lambda () x))))
    x))

> ones
'(1 . #<procedure>)
> ((cdr ones))
'(1 . #<procedure>)

身份检查验证循环性:

> (eq? ones ((cdr ones)))
#t

【讨论】:

    【解决方案2】:

    通过点击相关问题 (Why don't purely functional languages use reference counting?) 的链接,我看到了对 letrec 的引用。这让我意识到我确实可以在 Scheme 中创建一个循环的“数据结构”:

    (letrec ((add (lambda (x y) (if (>= x y) (+ x y) (add2 y x))))
             (add2 (lambda (x y) (if (>= x y) (+ x y) (add y x)))))
      (add 1 5))
    

    【讨论】:

      【解决方案3】:

      添加到@molbdnilo 回答大多数方案imeplemetation 定义delayforce, 允许创建所谓的流(定义在 SICP)。

      ; The infinite list (1 1 1 ...
      (define ones (cons 1 (delay ones)))
      
      > ones
      (1 . #<promise>)
      
      > (force (cdr ones))
      (1 . #<promise>)
      
      (eq? ones (force (cdr ones)))
      #t
      

      delayforce 可以实现为只是 lambda 表达式的宏。您甚至可以编写处理流的过滤器或映射等过程。

      编辑:

      同样由 R7RS 定义,您可以创建带有基准标签的真实循环列表。

      (define x '#0=(a b c . #0#))
      x
      ;; ==> #0=(a b c . #0#)
      (eq? x (cdddr x))
      #t
      

      如果 Scheme 完全支持 R7RS 规范,它应该允许以相同的方式定义和显示循环列表。请注意,在 Kawa Scheme 中,它将循环打印以显示您需要使用 (write x) 的循环列表。

      【讨论】:

      • 谢谢!这比使用letrec 的解决方案更简单、更纯粹。
      • @EllenSpertus 我还需要更新,因为 R7RS 中定义的方案还允许创建带有基准标签的循环列表。
      猜你喜欢
      • 2018-07-23
      • 1970-01-01
      • 1970-01-01
      • 2019-03-11
      • 2013-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多