将函数作为参数传递但得到意外结果

发布于 2024-10-12 22:09:18 字数 709 浏览 6 评论 0原文

我正在使用具有“高级学生”语言设置的 Racket,并且我在尝试编写一个函数来获取一个函数、执行它 n 次并报告每次运行所用的时间时遇到困难。这就是我到目前为止所得到的。

(define (many n fn)
  (cond
    [(= n 0) true]
    [else (many (sub1 n) (local ((define k (time fn))) k))]))

我有一个名为 fact 的函数,它计算数字的阶乘。

(define (fact n)
  (cond
    [(= 0 n) 1]
    [else (* n (fact (- n 1)))]))

如果我评估 (time (fact 10000)),我会得到 cpu、实际时间和 gc 时间以及大量数字的合理结果。一切都很好。

但是,当我尝试评估 (many 3 (fact 10000)) 时,我得到:

cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
true

尽管作为参数传递,但为什么该函数没有评估 fact

I'm using Racket with the "Advanced Student" language setting and I'm having difficulty trying to write a function that takes a function, executes it n times and reports the time elapsed for each run. This is what I've got so far.

(define (many n fn)
  (cond
    [(= n 0) true]
    [else (many (sub1 n) (local ((define k (time fn))) k))]))

I have a function called fact that computes the factorial of a number.

(define (fact n)
  (cond
    [(= 0 n) 1]
    [else (* n (fact (- n 1)))]))

If I evaluate (time (fact 10000)), I get reasonable results for cpu, real and gc time, as well as a large number. All well and good.

However, when I try to evaluate (many 3 (fact 10000)) I get:

cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
true

Why is the function not evaluating fact despite being passed as a parameter?

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

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

发布评论

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

评论(1

梦途 2024-10-19 22:09:18

让我们来看看 many 做了什么。首先定义它:

(define (many n fn)
  (cond
    [(= n 0) true]
    [else (many (sub1 n) 
                (local ((define k (time fn))) 
                       k))]))

然后调用它:当

> (many 3 (add1 41))
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
#t
> 

many 递归地调用自身时,每次迭代时会发生什么:

(define (many 3 42)
  (cond
    [(= 3 0) true]
    [else (many (sub1 3) 
                (local ((define k (time 42))) 
                       42))]))

(define (many 2 42)
  (cond
    [(= 2 0) true]
    [else (many (sub1 2) 
                (local ((define k (time 42))) 
                       42))]))

(define (many 1 42)
  (cond
    [(= 1 0) true]
    [else (many (sub1 1) 
                (local ((define k (time 42))) 
                       42))]))

(define (many 0 42)
  (cond
    [(= 0 0) true]
    [else (many (sub1 0) 
                (local ((define k (time 42))) 
                       42))]))

您对 many 的定义使用第一个 many 的结果值递归地调用自身code>(time fn) 应用程序,但它不正确,因为您想要收集过程应用程序的计时信息,而不是值(在我们的示例中为 (add1 41) 的值) )。只需在 many 的定义中将 true 替换为 fn

(define (many n fn)
  (cond
    [(= n 0) fn]
    [else (many (sub1 n) 
                (local ((define k (time fn))) 
                 k))]))

,您将得到以下结果:

> (many 3 (add1 41))
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
42
>

您会看到 fn > 每次递归调用都等于42。发生这种情况是因为许多(如果不是全部)FP 语言使用应用顺序求值,并且< code>(add1 41) 在第一次调用 many 发生之前进行评估。

因此,我们必须使用 lambda 来确保函数(在我们的例子中是 thunk)作为第二个参数(fn )。正如您已经知道的,Scheme 中的函数应用表示为表达式周围的 ()

(define (many n fn)  
  (time (fn))  
  (if (= n 0) 
      true
      (many (sub1 n) fn)))

输出示例:

> (many 3 (lambda () (fact 10000)))
cpu time: 2734 real time: 2828 gc time: 1922
cpu time: 906 real time: 953 gc time: 171
cpu time: 891 real time: 953 gc time: 204
cpu time: 938 real time: 984 gc time: 251
#t
>

如上所示 (fn) 执行函数 结果的应用(lambda () (fact 10000) (thunk),<​​code>time 准确获取您想要传递给它的内容(表达式)并显示正确的计时信息。

希望有所帮助。如果有请纠正我我错了。

Let's examine what you many does. First you defined it:

(define (many n fn)
  (cond
    [(= n 0) true]
    [else (many (sub1 n) 
                (local ((define k (time fn))) 
                       k))]))

Then call it:

> (many 3 (add1 41))
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
#t
> 

Here what happens on every iteration when many calls itself recursively:

(define (many 3 42)
  (cond
    [(= 3 0) true]
    [else (many (sub1 3) 
                (local ((define k (time 42))) 
                       42))]))

(define (many 2 42)
  (cond
    [(= 2 0) true]
    [else (many (sub1 2) 
                (local ((define k (time 42))) 
                       42))]))

(define (many 1 42)
  (cond
    [(= 1 0) true]
    [else (many (sub1 1) 
                (local ((define k (time 42))) 
                       42))]))

(define (many 0 42)
  (cond
    [(= 0 0) true]
    [else (many (sub1 0) 
                (local ((define k (time 42))) 
                       42))]))

Your definition of many recursively calls itself with the result value of the first (time fn) application, but it is not correct, because you want to collect timing information for your procedure application, not the value (value of (add1 41) in our case). Just substitute true with fn in your definition of many:

(define (many n fn)
  (cond
    [(= n 0) fn]
    [else (many (sub1 n) 
                (local ((define k (time fn))) 
                 k))]))

and you'll get the following:

> (many 3 (add1 41))
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
42
>

You see that fn on every recursive call equals 42. This happens because many (if not all) FP languages use Applicative order of evaluation, and (add1 41) is evaluated before the first call to many happens.

Thus we have to use lambda to ensure a function (thunk in our case) is passed to many as it's second argument (fn). As you already know function application in Scheme is expressed as () around expression:

(define (many n fn)  
  (time (fn))  
  (if (= n 0) 
      true
      (many (sub1 n) fn)))

Example output:

> (many 3 (lambda () (fact 10000)))
cpu time: 2734 real time: 2828 gc time: 1922
cpu time: 906 real time: 953 gc time: 171
cpu time: 891 real time: 953 gc time: 204
cpu time: 938 real time: 984 gc time: 251
#t
>

As you see above (fn) performs application of the result of function (lambda () (fact 10000) (thunk), time gets exactly what you wanted to pass it (an expression) and displays the correct timing information.

Hope that helps. Correct me if I'm wrong.

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