Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 函数指针、闭包和Lambda_C_Lisp_Lambda_Computer Science_Closures - Fatal编程技术网

C 函数指针、闭包和Lambda

C 函数指针、闭包和Lambda,c,lisp,lambda,computer-science,closures,C,Lisp,Lambda,Computer Science,Closures,我刚刚学习了函数指针,当我阅读K&R一章时,我第一个想到的是,“嘿,这有点像一个结尾。”我知道这个假设在某种程度上是错误的,在网上搜索之后,我没有找到任何关于这个比较的分析 那么,为什么C风格的函数指针与闭包或lambda有根本的不同呢?据我所知,这与函数指针仍然指向已定义(命名)函数这一事实有关,与匿名定义函数的做法相反 为什么在第二种情况下(未命名)将函数传递给一个函数比第一种情况下(传递的只是一个普通的日常函数)更强大 请告诉我,我如何以及为什么不对这两者进行如此密切的比较 谢谢。在C语言

我刚刚学习了函数指针,当我阅读K&R一章时,我第一个想到的是,“嘿,这有点像一个结尾。”我知道这个假设在某种程度上是错误的,在网上搜索之后,我没有找到任何关于这个比较的分析

那么,为什么C风格的函数指针与闭包或lambda有根本的不同呢?据我所知,这与函数指针仍然指向已定义(命名)函数这一事实有关,与匿名定义函数的做法相反

为什么在第二种情况下(未命名)将函数传递给一个函数比第一种情况下(传递的只是一个普通的日常函数)更强大

请告诉我,我如何以及为什么不对这两者进行如此密切的比较


谢谢。

在C语言中,您不能内联定义函数,因此无法真正创建闭包。您所做的只是传递对某个预定义方法的引用。在支持匿名方法/闭包的语言中,方法的定义要灵活得多

用最简单的术语来说,函数指针没有与其关联的作用域(除非计算全局作用域),而闭包包含定义它们的方法的作用域。使用lambdas,您可以编写一个编写方法的方法。闭包允许您将“一些参数绑定到一个函数,从而得到一个较低的arity函数。”(摘自Thomas的评论)。在C语言中你不能这么做

编辑:添加一个示例(我将使用Actionscript ish语法,因为这正是我现在想到的):

假设您有一个以另一个方法为参数的方法,但在调用该方法时没有提供向该方法传递任何参数的方法?比如说,某个方法在运行您传递的方法之前会导致延迟(愚蠢的示例,但我希望保持简单)

现在假设您想使用runLater()延迟对象的某些处理:

function objectProcessor(o:Object):Void {
  /* Do something cool with the object! */
}

function process(o:Object):Void {
  runLater(function() { objectProcessor(o); });
}
传递给process()的函数不再是静态定义的函数。它是动态生成的,并且能够包含对定义方法时在范围内的变量的引用。因此,它可以访问“o”和“objectProcessor”,即使它们不在全局范围内


我希望这是有意义的。

闭包=逻辑+环境

例如,考虑这一C 3方法:

public Person FindPerson(IEnumerable<Person> people, string name)
{
    return people.Where(person => person.Name == name);
}
public Person FindPerson(IEnumerable people,字符串名)
{
返回people.Where(person=>person.Name==Name);
}
lambda表达式不仅封装了逻辑(“比较名称”),还封装了环境,包括参数(即局部变量)“名称”


有关这方面的更多信息,请看我的,它将带您浏览C#1、2和3,展示闭包如何使事情变得更简单。

主要区别在于C中缺少词汇范围

函数指针就是指向代码块的指针。它引用的任何非堆栈变量都是全局的、静态的或类似的

闭包OTOH以“外部变量”或“upvalues”的形式拥有自己的状态。它们可以是私有的,也可以是共享的。可以使用相同的函数代码创建许多闭包,但变量和实例不同

一些闭包可以共享一些变量,因此可以作为对象的接口(在OOP意义上)。要在C中实现这一点,必须将结构与函数指针表(即C++的类VTABLE)关联。 简而言之,闭包是一个函数指针加上一些状态。lambda是一个匿名的、动态定义的函数。你就是不能在C。。。对于闭包(或两者的合并),典型的lisp示例将大致如下所示:

(defun get-counter (n-start +-number)
     "Returns a function that returns a number incremented
      by +-number every time it is called"
    (lambda () (setf n-start (+ +-number n-start))))
在C语言中,您可以说,
get counter
的词法环境(堆栈)被匿名函数捕获,并在内部进行修改,如下例所示:

[1]> (defun get-counter (n-start +-number)
         "Returns a function that returns a number incremented
          by +-number every time it is called"
        (lambda () (setf n-start (+ +-number n-start))))
GET-COUNTER
[2]> (defvar x (get-counter 2 3))
X
[3]> (funcall x)
5
[4]> (funcall x)
8
[5]> (funcall x)
11
[6]> (funcall x)
14
[7]> (funcall x)
17
[8]> (funcall x)
20
[9]> 
lambda(or)封装函数指针和变量。这就是为什么在C#中,您可以执行以下操作:

int lessThan = 100;
Func<int, bool> lessThanTest = delegate(int i) {
   return i < lessThan;
};
int-lessThan=100;
Func lessThanTest=委托(int i){
返回i
我在那里使用了一个匿名委托作为闭包(它的语法比lambda等价物更清晰,更接近C),它将lessThan(一个堆栈变量)捕获到闭包中。在计算闭包时,lessThan(其堆栈框架可能已被破坏)将继续被引用。如果我更改lessThan,那么我将更改比较:

int lessThan = 100;
Func<int, bool> lessThanTest = delegate(int i) {
   return i < lessThan;
};

lessThanTest(99); // returns true
lessThan = 10;
lessThanTest(99); // returns false
int-lessThan=100;
Func lessThanTest=委托(int i){
返回i
在C中,这是非法的:

BOOL (*lessThanTest)(int);
int lessThan = 100;

lessThanTest = &LessThan;

BOOL LessThan(int i) {
   return i < lessThan; // compile error - lessThan is not in scope
}
BOOL(*lessThanTest)(int);
int-lessThan=100;
lessthanst=&LessThan;
布尔-莱斯特尚(国际一){
返回i
虽然我可以定义一个包含两个参数的函数指针:

int lessThan = 100;
BOOL (*lessThanTest)(int, int);

lessThanTest = &LessThan;
lessThanTest(99, lessThan); // returns true
lessThan = 10;
lessThanTest(100, lessThan); // returns false

BOOL LessThan(int i, int lessThan) {
   return i < lessThan;
}
int-lessThan=100;
BOOL(*lessthatest)(int,int);
lessthanst=&LessThan;
Lessthanst(99,lessThan);//返回true
lessThan=10;
lessthanst(100,lessThan);//返回false
布尔-莱斯坦(国际一级,国际莱斯坦){
返回i
但是,现在我必须在计算它时传递这两个参数。如果我希望将此函数指针传递到lessThan不在作用域内的另一个函数,我必须手动将其保持活动状态,方法是将其传递给链中的每个函数,或者将其升级到全局函数

尽管大多数支持闭包的主流语言都使用匿名函数,但并不需要匿名函数。可以使用不带匿名函数的闭包,也可以使用不带闭包的匿名函数

摘要:闭包是函数的组合
int lessThan = 100;
BOOL (*lessThanTest)(int, int);

lessThanTest = &LessThan;
lessThanTest(99, lessThan); // returns true
lessThan = 10;
lessThanTest(100, lessThan); // returns false

BOOL LessThan(int i, int lessThan) {
   return i < lessThan;
}
{
    my $count;
    sub increment { return $count++ }
}
#define lambda(l_ret_type, l_arguments, l_body)       \
({                                                    \
    l_ret_type l_anonymous_functions_name l_arguments \
    l_body                                            \
    &l_anonymous_functions_name;                      \
})
qsort (array, sizeof (array) / sizeof (array[0]), sizeof (array[0]),
     lambda (int, (const void *a, const void *b),
             {
               dump ();
               printf ("Comparison %d: %d and %d\n",
                       ++ comparison, *(const int *) a, *(const int *) b);
               return *(const int *) a - *(const int *) b;
             }));
CL-USER 53 > (defun make-adder (start delta) (lambda () (incf start delta)))
MAKE-ADDER

CL-USER 54 > (compile *)
MAKE-ADDER
NIL
NIL
CL-USER 55 > (let ((adder1 (make-adder 0 10))
                   (adder2 (make-adder 17 20)))
               (print (funcall adder1))
               (print (funcall adder1))
               (print (funcall adder1))
               (print (funcall adder1))
               (print (funcall adder2))
               (print (funcall adder2))
               (print (funcall adder2))
               (print (funcall adder1))
               (print (funcall adder1))
               (describe adder1)
               (describe adder2)
               (values))

10 
20 
30 
40 
37 
57 
77 
50 
60 
#<Closure 1 subfunction of MAKE-ADDER 4060001ED4> is a CLOSURE
Function         #<Function 1 subfunction of MAKE-ADDER 4060001CAC>
Environment      #(60 10)
#<Closure 1 subfunction of MAKE-ADDER 4060001EFC> is a CLOSURE
Function         #<Function 1 subfunction of MAKE-ADDER 4060001CAC>
Environment      #(77 20)