与Lambdas一起玩耍

时间:2010-02-18 22:12:38

标签: function lambda language-agnostic closures

没有让他们使用它们我不太确定所有lambdas / blocks都可以用于(除了map / collect / do /轻量级本地函数语法)。如果有些人可以发布一些有趣但有些可理解的例子(有解释)。

示例的首选语言:python,smalltalk,haskell

6 个答案:

答案 0 :(得分:2)

您可以使用lambdas创建功能数据结构。这是一个简单的 - 功能列表(Python),支持addcontains方法:

empty = lambda x : None

def add(lst, item) :
    return lambda x : x == item or lst(x)

def contains(lst, item) :
    return lst(item) or False

我只是为了好玩而快速编码 - 请注意,您不能按原样添加任何虚假值。它也不是尾递归的,因为一个好的功能结构应该是。为读者练习!

答案 1 :(得分:2)

您可以将它们用于控制流程。例如,在Smalltalk中,“ifTrue:ifFalse:”方法是布尔对象上的一种方法,对True和False类中的每一个都有不同的实现。表达式

someBoolean ifTrue: [self doSomething] ifFalse: [self doSomethingElse]

在Smalltalk语法的[方括号]中使用两个闭包---块,一个用于真正的分支,一个用于假分支。对于类True的实例,“ifTrue:ifFalse:”的实现是

ifTrue: block1 ifFalse: block2
    ^ block1 value

,对于False类:

ifTrue: block1 ifFalse: block2
    ^ block2 value

此处的闭包用于延迟评估,以便可以在没有任何专门语法的情况下进行关于控制流的决策(除了块的语法)。

Haskell有点不同,它的懒惰评估模型在很多情况下有效地自动产生闭包的效果,但在Scheme中你最终使用lambdas来控制流量很多。例如,这是一个从关联列表中检索值的实用程序,在不存在该值的情况下提供可选计算的默认值:

(define (assq/default key lst default-thunk)
  (cond
    ((null? lst) (default-thunk)) ;; actually invoke the default-value-producer
    ((eq? (caar lst) key) (car lst))
    (else (assq/default key (cdr lst) default-thunk))))

它将被称为:

(assq/default 'mykey my-alist (lambda () (+ 3 4 5)))

这里的关键是使用lambda来延迟默认值的计算,直到它实际上已知是必需的。

另请参阅continuation-passing-style,它将此视为极端。例如,Javascript依赖于continuation-passing-style和closures来执行所有阻塞操作(如休眠,I / O等)。

ETA :我上面说的闭包,我的意思是词法范围闭包。通常,这是词汇范围的关键。

答案 2 :(得分:1)

你可以使用lambda来创建一个Y Combinator,它是一个接受另一个函数并返回它的递归形式的函数。这是一个例子:

def Y(le):
    def _anon(cc):
        return le(lambda x: cc(cc)(x))
    return _anon(_anon)

这是一个 思想打击 ,值得更多解释,但不是在这里反复检查this blog entry(上面的样本也来自那里)。

答案 3 :(得分:1)

它的C#,但每次我读到它时,我个人都会对这篇文章有所了解:

Building Data out of Thin Air - 在C#中实现Lisp的cons,car和cdr函数。它展示了如何完全用lambda函数构建一个简单的堆栈数据结构。

答案 4 :(得分:1)

与haskell等相同的概念并不是真的相当,但在C#中,lambda构造具有(可选)编译为表示代码的 objcet模型的能力< / em>(表达式树)而不是代码本身(这本身就是LINQ的基石之一)。

这反过来会导致一些非常富有表现力的元编程机会,例如(这里的lambda表示“给定服务,你想用它做什么?”):

var client = new Client<ISomeService>();
string captured = "to show a closure";
var result = client.Invoke(
    svc => svc.SomeMethodDefinedOnTheService(123, captured)
);

(假设合适的Invoke签名)

这种类型的东西有很多用途,但我用它来构建一个不需要任何运行时代码生成的RPC堆栈 - 它只是解析表达式树,找出调用者的意图,将其转换为RPC,调用它,收集响应等(更多地讨论here)。

答案 5 :(得分:0)

Haskell中使用数值近似来计算单个变量函数的导数的一个例子:

deriv f = \x -> (f (x + d) - f x) / d
  where
    d = 0.00001

f x = x ^ 2
f' = deriv f -- roughly equal to f' x = 2 * x