柯里化函数在Scheme中的实现

发布于 2024-07-09 18:08:14 字数 455 浏览 6 评论 0原文

当我执行以下操作时会发生什么?

(define ((func x) y)
    (if (zero? y)
        ((func x) 1)
        12))

我知道我可以这样做:

(define curried (func 5))

现在我可以使用柯里化。 我很好奇的是函数的定义。 该行是否

((func x) 1)

创建一个以 x 作为参数的新 lambda,然后在 1 上调用它? 或者它比这更聪明,它只是重复使用现有的。 (例如,如果我执行 (curried 0),则 ((func x) 1) 行将相当于 (curried 1) - PLAI计划可以做到这一点吗?)

What happens when I do the following?

(define ((func x) y)
    (if (zero? y)
        ((func x) 1)
        12))

I understand that I can do this:

(define curried (func 5))

And now I can use curried. What I'm curious about is in the definition of the function. Does the line

((func x) 1)

create a new lambda with x as the argument, and then invoke it on 1? Or is it smarter than that and it just re-uses the existing one. (For example, if I do (curried 0), the ((func x) 1) line would be equivalent to (curried 1) - does PLAI Scheme do this?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

捎一片雪花 2024-07-16 18:08:14

在Scheme标准中指定了

(define (f x) 42) is short for (define f (lambda (x) 42)) .

自然(非标准)泛化意味着:

(define ((f x) y) (list x y)) is short for (define (f x) (lambda (y) (list x y)))
                which is short for (define f (lambda (x) (lambda (y) (list x y))))

中的示例

为了测试它,让我们尝试DrScheme欢迎使用DrScheme版本4.1.3.3-svn5dec2008 [3m] 。
语言:模块; 内存限制:384 MB。

(定义((fx)y)(列表xy))
(f 1)

((f 1) 2)
(1 2)

如果我们命名临时值,可能会更容易看出会发生什么:

(定义 h (f 1))
(小时2)
(1 2)
(小时3)
(1 3)

由于“PLAIScheme”是在DrScheme中实现的,我相信它继承了这个快捷符号。

In the Scheme standard it is specified that

(define (f x) 42) is short for (define f (lambda (x) 42)) .

The natural (non-standard) generalization implies:

(define ((f x) y) (list x y)) is short for (define (f x) (lambda (y) (list x y)))
                which is short for (define f (lambda (x) (lambda (y) (list x y))))

To test it, let's try the example in DrScheme

Welcome to DrScheme, version 4.1.3.3-svn5dec2008 [3m].
Language: Module; memory limit: 384 megabytes.

(define ((f x) y) (list x y))
(f 1)

((f 1) 2)
(1 2)

If we name the temporary value, it might be easier to see what happens:

(define h (f 1))
(h 2)
(1 2)
(h 3)
(1 3)

Since "PLAI Scheme" is implemented in DrScheme, I believe it inherits this shortcut notation.

因为看清所以看轻 2024-07-16 18:08:14

It's been too long since I worked with scheme, but you might find this article helpful.
It describes the implementation of two macros, c-lambda and c-define which allow implicit curried definitions of lambda expressions.

寻找我们的幸福 2024-07-16 18:08:14

soegaard的答案是正确的——这是传统的展开。 不过,drscheme 很聪明!

我发现以下代码在运行时间上是等效的:

原始来源:

(define ((substitute lv value) e)
  (cond [(LogicVar? e)
     (type-case LogicVar e
       [lv-any (id) (if (symbol=? id (lv-any-id lv))
                value
                e)]
       [lv-cons (f r) 
            (lv-cons ((substitute lv value) f)
                 ((substitute lv value) r))])]
    [(cons? e)
     (cons ((substitute lv value) (car e))
           ((substitute lv value) (cdr e)))]
    [else e]))

尝试优化:

(define (substitute lv value)
  (local ([define inner
        (lambda (e)
          (cond [(LogicVar? e)
             (type-case LogicVar e
               [lv-any (id) (if (symbol=? id (lv-any-id lv))
                    value
                    e)]
               [lv-cons (f r) 
                (lv-cons (inner f)
                     (inner r))])]
            [(cons? e)
             (cons (inner (car e))
               (inner (cdr e)))]
            [else e]))])
    inner))

大量使用此函数(多次,而不是一次)的代码对于两个版本都以 1800 毫秒运行。 更有趣的是,这个版本(我对所发生情况的可视化):

(define (substitute lv value)
  (local ([define inner
        (lambda (e)
          (cond [(LogicVar? e)
             (type-case LogicVar e
               [lv-any (id) (if (symbol=? id (lv-any-id lv))
                    value
                    e)]
               [lv-cons (f r) 
                (lv-cons ((substitute lv value) f)
                     ((substitute lv value) r))])]
            [(cons? e)
             (cons ((substitute lv value) (car e))
               ((substitute lv value) (cdr e)))]
            [else e]))])
    inner))

运行时间为 2000 毫秒。 因此,如果对替换内替换的调用每次都创建一个 lambda,那么速度肯定会变慢,但快捷表示法似乎并非如此。

soegaard's answer is correct - this is the traditional expansion. However, drscheme is smart!

The following code I've found to be equivalent in running time:

Original source:

(define ((substitute lv value) e)
  (cond [(LogicVar? e)
     (type-case LogicVar e
       [lv-any (id) (if (symbol=? id (lv-any-id lv))
                value
                e)]
       [lv-cons (f r) 
            (lv-cons ((substitute lv value) f)
                 ((substitute lv value) r))])]
    [(cons? e)
     (cons ((substitute lv value) (car e))
           ((substitute lv value) (cdr e)))]
    [else e]))

Attempt at optimization:

(define (substitute lv value)
  (local ([define inner
        (lambda (e)
          (cond [(LogicVar? e)
             (type-case LogicVar e
               [lv-any (id) (if (symbol=? id (lv-any-id lv))
                    value
                    e)]
               [lv-cons (f r) 
                (lv-cons (inner f)
                     (inner r))])]
            [(cons? e)
             (cons (inner (car e))
               (inner (cdr e)))]
            [else e]))])
    inner))

Code which heavily uses this function (multiple times, not just once) runs at 1800 ms for both versions. More interestingly, this version (my visualization of what was happening):

(define (substitute lv value)
  (local ([define inner
        (lambda (e)
          (cond [(LogicVar? e)
             (type-case LogicVar e
               [lv-any (id) (if (symbol=? id (lv-any-id lv))
                    value
                    e)]
               [lv-cons (f r) 
                (lv-cons ((substitute lv value) f)
                     ((substitute lv value) r))])]
            [(cons? e)
             (cons ((substitute lv value) (car e))
               ((substitute lv value) (cdr e)))]
            [else e]))])
    inner))

Runs at 2000 ms. So there is definitely a slow-down if the calls to substitute within substitute were each creating a lambda, but it appears this is not the case with the shortcut notation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文