在计划中展开功能

Dan*_* P. 3 lisp scheme racket

目标:unfold仅使用两个参数实现函数.

论点:

  • 第一个参数是f,它接受某个类型I的初始值并返回nil或两个元素的cons对(这两个元素中的第一个是进入某个类型A的列表中的下一个元素,再次是下一个初始值某些类型I).
  • 第二个参数是某个类型I的初始值,返回值是类型A的项目列表.

这是我到目前为止,我不知道为什么它不起作用:

(define (descending i)
  (if (= i 0)
    (list)
    (cons i (- i 1))))

(define nil (list))

(define (unfold f init)
  (if (eq? (f init) '())
    (list)
    (cons init (unfold f (f init)))))

(unfold (descending 5))
Run Code Online (Sandbox Code Playgroud)

应该评估

'(5 4 3 2 1)
Run Code Online (Sandbox Code Playgroud)

这应该是结果,但事实并非如此.我究竟做错了什么?

Dan*_*her 5

首先,它应该是(unfold descending 5).然后f会产生一对,你会使用它的两个组成部分,

(define (unfold f init)
  (if (eq? (f init) '())
      (list)
      (cons (car (f init)) (unfold f (cdr (f init))))))
Run Code Online (Sandbox Code Playgroud)

但这具有可怕的计算复杂性,因为它(f init)每次迭代调用三次.谦虚的let约束力可以解决这个问题.

(define (unfold f init)
  (let ((r (f init)))
    (if (empty? r) ;; instead of (eq? r '())
        (list)
        (cons (car r) (unfold f (cdr r))))))
Run Code Online (Sandbox Code Playgroud)

并使用命名的尾递归形式let

(define (unfold f init)
  (let loop ((acc empty)
             (state (f init)))
    (if (empty? state)
        (reverse acc)
        (loop (cons (car state) acc)
              (f (cdr state))))))
Run Code Online (Sandbox Code Playgroud)

并使用match.

(define (unfold f init)
  (let loop ((acc empty)
             (state (f init)))
    (match state
      ((cons x next)
       (loop (cons x acc)
             (f next)))
      (empty
       (reverse acc)))))
Run Code Online (Sandbox Code Playgroud)