【发布时间】:2014-02-19 04:32:14
【问题描述】:
我必须编写一个名为 curry-skip 的方案函数,它递归地返回列表的第 n 个元素,这样
(((curry-skip 1) 'foo) 'bar) => bar
我似乎无法弄清楚如何递归地执行此操作。我对Scheme还是很陌生,所以任何帮助都将不胜感激! 谢谢
【问题讨论】:
我必须编写一个名为 curry-skip 的方案函数,它递归地返回列表的第 n 个元素,这样
(((curry-skip 1) 'foo) 'bar) => bar
我似乎无法弄清楚如何递归地执行此操作。我对Scheme还是很陌生,所以任何帮助都将不胜感激! 谢谢
【问题讨论】:
(define (curry-skip n)
(if (zero? n)
(lambda (x) x)
(let ((rest (curry-skip (- n 1))))
(lambda (x) rest))))
您想计算返回的lambda 之外的(- n 1) 案例外部!因此,在上面,当n 为零时,只需返回一个参数 lambda;但是,当n 为正时,计算(- n 1) 的情况并返回忽略其参数并仅返回rest 的lambda。
请注意,虽然不是您的问题的一部分,但与评论相关,但如果您需要真正的咖喱,就像在 ML 中一样,您需要语法帮助:
(define-syntax curry*
(syntax-rules ()
((_ (a) body ...) (lambda (a) body ...))
((_ (a b ...) body ...)
(lambda (a) (curry* (b ...) body ...)))))
注意递归如何为每个a, b, … 创建词法环境,以便可以正确评估body。 curry-skip 没有这种需求。
这里有一些代码解决了关于在返回的 lambda 中执行“curry-skip”的注释。在lambda 之外进行递归只会在创建一个闭包时发生;在 lambda 内执行此操作会在每次调用时创建闭包。
(define (curry-skip-o n)
(if (zero? n)
(lambda (x) x)
(let ((rest (curry-skip-o (- n 1))))
(lambda (x) rest))))
(define (curry-skip-i n)
(if (zero? n)
(lambda (x) x)
(lambda (x) (curry-skip-i (- n 1)))))
(define (run skipper r n)
(let ((f (skipper n)))
;; Repeat 'r' times with 'f'
(let rep ((r r))
(unless (zero? r)
;; Exhaust f
(let rep ((i 0) (f f))
(if (< i n)
(rep (+ i 1) (f i))
(f 0)))
(rep (- r 1))))))
> (time (run curry-skip-o 10000 10000)) ;; create ~10^4 closures
running stats for (run curry-skip-o 10000 10000):
no collections
376 ms elapsed cpu time, including 0 ms collecting
376 ms elapsed real time, including 0 ms collecting
160032 bytes allocated
> (time (run curry-skip-i 10000 10000)) ;; create ~10^8 closures
running stats for (run curry-skip-i 10000 10000):
191 collections
1587 ms elapsed cpu time, including 965 ms collecting
1588 ms elapsed real time, including 966 ms collecting
1599840048 bytes allocated
【讨论】:
我认为你这里有 3 个案例:
所以
(define (res val) ; [procedure used for case 2 - n=0]
(define (res0 . x) (if (null? x) val res0)) ; [case 3]
res0)
(define (curry-skip n)
(cond
((< n 0) (error "n is negative"))
((= n 0) res) ; [case 2 - n = 0]
(else (lambda x (curry-skip (- n 1)))))) ; [case 1 - n > 0]
然后
-> (((curry-skip 0) 'foo))
'foo
-> ((((curry-skip 0) 'foo) 'bar))
'foo
-> ((((curry-skip 1) 'foo) 'bar))
'bar
-> (((((curry-skip 0) 'foo) 'bar) 'baz))
'foo
-> (((((curry-skip 1) 'foo) 'bar) 'baz))
'bar
-> (((((curry-skip 2) 'foo) 'bar) 'baz))
'baz
与您的问题相比,我的解决方案多了一对括号,但这是我所能得到的。
【讨论】:
看了你的例子后,我写了以下内容。这似乎相当简单,因此我无法解释它的原因。
(define (curry-skip n)
(lambda (v) (if (= n 0)
v
(curry-skip (- n 1)))))
【讨论】: