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

Gre*_*orn 1 lambda scheme functional-programming operator-precedence racket

我正在使用具有"高级学生"语言设置的Racket,并且我很难尝试编写一个函数来执行函数,执行n次并报告每次运行所用的时间.这是我到目前为止所得到的.

(define (many n fn)
  (cond
    [(= n 0) true]
    [else (many (sub1 n) (local ((define k (time fn))) k))]))
Run Code Online (Sandbox Code Playgroud)

我有一个函数叫做fact计算数字的阶乘.

(define (fact n)
  (cond
    [(= 0 n) 1]
    [else (* n (fact (- n 1)))]))
Run Code Online (Sandbox Code Playgroud)

如果我评估(time (fact 10000)),我得到合理的结果cpu,real和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
Run Code Online (Sandbox Code Playgroud)

fact尽管作为参数传递,为什么函数不进行评估?

Yas*_*aev 5

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

(define (many n fn)
  (cond
    [(= n 0) true]
    [else (many (sub1 n) 
                (local ((define k (time fn))) 
                       k))]))
Run Code Online (Sandbox Code Playgroud)

然后叫它:

> (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
> 
Run Code Online (Sandbox Code Playgroud)

这里在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))]))
Run Code Online (Sandbox Code Playgroud)

many使用第一个(time fn)应用程序的结果值递归调用自身的定义,但它不正确,因为您希望收集过程应用程序的定时信息,而不是值((add1 41)在我们的情况下为值).刚刚替补truefn你的定义many:

(define (many n fn)
  (cond
    [(= n 0) fn]
    [else (many (sub1 n) 
                (local ((define k (time fn))) 
                 k))]))
Run Code Online (Sandbox Code Playgroud)

你会得到以下内容:

> (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
>
Run Code Online (Sandbox Code Playgroud)

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

因此,我们必须使用lambda确保函数(在我们的例子中为thunk)作为第二个参数(fn)传递给许多函数.正如您所知,Scheme中的函数应用表达为()表达式:

(define (many n fn)  
  (time (fn))  
  (if (= n 0) 
      true
      (many (sub1 n) fn)))
Run Code Online (Sandbox Code Playgroud)

示例输出:

> (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
>
Run Code Online (Sandbox Code Playgroud)

如上所示,(fn)执行函数(lambda () (fact 10000)(thunk)结果的应用程序,time获得您想要传递的结果(表达式)并显示正确的计时信息.

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