何时何地使用Lambda?

时间:2010-12-04 05:59:25

标签: ruby language-agnostic lambda

我试图理解为什么我们真的需要rubda(或任何其他语言)的lambda或proc?

#method
def add a,b
  c = a+b
end

#using proc
def add_proc a,b
  f = Proc.new {|x,y| x + y }
  f.call a,b
end

#using lambda function
def add_lambda a,b
  f = lambda {|x,y| x + y}
  f.call a,b
end

puts add 1,1
puts add_proc 1,2
puts add_lambda 1,3

我可以使用以下方法进行简单的添加:1。正常功能def,2。使用proc和3.使用lambda。

但是为什么以及在现实世界中使用lambda?任何不能使用函数和lambda应该使用的例子。

7 个答案:

答案 0 :(得分:20)

确实,你不需要需要匿名函数(或者lambda,或者你想要的任何东西)。但是你有很多事情不需要。您不需要类 - 只需将所有实例变量传递给普通函数。然后

class Foo
  attr_accessor :bar, :baz
  def frob(x)
    bar = baz*x
  end
end

会变成

def new_Foo(bar,baz)
  [bar,baz]
end

def bar(foo)
  foo[0]
end
# Other attribute accessors stripped for brevity's sake

def frob(foo,x)
  foo[0] = foo[1]*x
end

同样,除了loop...end ifbreak之外,您不需要 任何循环。我可以继续。 1 但是你希望用Ruby编写类。您希望能够使用while循环,甚至可能array.each { |x| ... },并且您希望能够使用unless代替if not

就像这些功能一样,匿名功能可以帮助您优雅,简洁,明智地表达事物。能够写some_function(lambda { |x,y| x + f(y) })比写

更好
def temp(x,y)
  x + f(y)
end
some_function temp

必须中断代码流以写出def馈送函数,然后必须给出一个无用的名称,这一点很笨重,因为它可以在线编写操作。确实,你无处必须使用lambda,但是我有很多地方而不是使用lambda。

Ruby使用块解决了很多使用lambda的案例:像eachmapopen这样可以将块作为参数的所有函数基本上都是特殊的匿名功能。 array.map { |x| f(x) + g(x) }array.map(&lambda { |x| f(x) + g(x) })相同(其中&只是使lambda“特殊”与裸块相同)。同样,你可以每次都写出一个单独的def fed函数 - 但为什么你想要

支持这种编程风格的Ruby以外的语言没有块,但通常支持更轻量级的lambda语法,例如Haskell的\x -> f x + g x或C#的x => f(x) + g(x); 2 < / SUP>。每当我有一个需要采取某些抽象行为的函数时,例如mapeachon_clicked,我都会感谢能够传递一个lambda而不是命名函数,因为它只是更容易。最终,你不再认为它们有点特别 - 它们与数组的文字语法而不是empty().append(1).append(2).append(3)一样令人兴奋。只是该语言的另一个有用部分。


1:在堕落的情况下,您实际上只需要eight instructions+-<>[].,<>沿着数组移动一个虚构的“指针”; +-递增和递减当前单元格中的整数; []执行非零循环;和.,做输入和输出。实际上,您实际上只需要one instruction,例如subleq a b c(从a减去b,如果结果小于或等于,则跳转到c零)。

2:我从未真正使用过C#,所以如果该语法错误,请随时更正。

答案 1 :(得分:6)

块或多或少是相同的东西

嗯,在Ruby中,通常不会使用lambda或proc,因为块大致相同并且更方便。

用途是无限的,但我们可以列出一些典型案例。人们通常认为函数是执行一部分处理的低级块,可能通常是编写并制作成库。

但通常人们想要自动化包装器并提供自定义库。想象一下,使HTTP或HTTPS连接或直接TCP连接的函数将I / O提供给其客户端,然后关闭连接。或者也许用普通的旧文件做同样的事情。

所以在Ruby中我们会把这个函数放在一个库中并让它为用户占用一个块...客户端......“调用者”来编写他的应用程序逻辑。

在另一种语言中,这必须通过实现接口或函数指针的类来完成。 Ruby有块,但它们都是lambda样式设计模式的例子。

答案 2 :(得分:6)

归结为风格。 Lambdas是一种陈述式的风格,方法是势在必行的风格。考虑一下:

Lambda,blocks,procs都是不同类型的闭包。现在的问题是,何时以及为何使用匿名闭包。我可以回答 - 至少在红宝石中!

闭包包含从中调用它们的词汇上下文。如果从方法中调用方法,则不会获得调用方法的上下文。这是由于对象链存储在AST中的方式。

另一方面,闭包(lambda)可以通过方法传递词汇上下文,允许进行惰性求值。

lambdas自然也适用于递归和枚举。

答案 3 :(得分:5)

1)这只是一种便利。您不需要命名某些块

special_sort(array, :compare_proc => lambda { |left, right| left.special_param <=> right.special_param }

(想象一下,如果你必须命名所有这些块)

2)#lambda通常用于创建clojures:

def generate_multiple_proc(cofactor)
  lambda { |element| element * cofactor }
end

[1, 2, 3, 4].map(&generate_multiple_proc(2)) # => [2, 3, 5, 8]

[1, 2, 3, 4].map(&generate_multiple_proc(3)) # => [3, 6, 9, 12]

答案 4 :(得分:2)

我发现这有助于理解差异:

http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/

但总的来说,关键是你有时候写一个方法,但是你不知道在那个方法中某个点你想做什么,所以你让调用者决定。

E.g:

def iterate_over_two_arrays(arr1, arr2, the_proc)
  arr1.each do |x|
    arr2.each do |y|
      # ok I'm iterating over two arrays, but I could do lots of useful things now
      #  so I'll leave it up to the caller to decide by passing in a proc
      the_proc.call(x,y)
    end
  end
end

然后,您只需拨打iterate_over_two_arrays_and_print_sum方法和iterate_over_two_arrays_and_print_product方法,而不是:

iterate_over_two_arrays([1,2,3], [4,5,6], Proc.new {|x,y| puts x + y }

iterate_over_two_arrays([1,2,3], [4,5,6], Proc.new {|x,y| puts x * y }

所以它更灵活。

答案 5 :(得分:2)

对于OOP,只有在根据域建模对类进行此类操作时,才应在类中创建函数。

如果您需要一个可以内联编写的快速功能,例如比较等,请使用lambda

同时查看这些SO帖子 -

When to use lambda, when to use Proc.new?

C# Lambda expressions: Why should I use them?

When to use a lambda in Ruby on Rails?

答案 6 :(得分:2)

它们被用作“高阶”功能。基本上,对于将一个函数传递给另一个函数的情况,接收函数可以根据自己的逻辑调用传入函数。

这在Ruby中常见,用于迭代,例如some_list.each {| item | ...}对each的{​​{1}} item做某事。虽然请注意我们不使用关键字some_list;如上所述,块基本上是相同的。

在Python中(因为我们在这个问题上有一个lambda标签)你不能写任何类似Ruby块的东西,所以language-agnostic关键字会更频繁地出现。但是,您可以从列表推导和生成器表达式中获得类似的“快捷方式”效果。