我试图理解为什么我们真的需要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应该使用的例子。
答案 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
if
和break
之外,您不需要 任何循环。我可以继续。 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的案例:像each
,map
和open
这样可以将块作为参数的所有函数基本上都是特殊的匿名功能。 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>。每当我有一个需要采取某些抽象行为的函数时,例如map
,each
或on_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?
答案 6 :(得分:2)
它们被用作“高阶”功能。基本上,对于将一个函数传递给另一个函数的情况,接收函数可以根据自己的逻辑调用传入函数。
这在Ruby中常见,用于迭代,例如some_list.each {| item | ...}对each
的{{1}} item
做某事。虽然请注意我们不使用关键字some_list
;如上所述,块基本上是相同的。
在Python中(因为我们在这个问题上有一个lambda
标签)你不能写任何类似Ruby块的东西,所以language-agnostic
关键字会更频繁地出现。但是,您可以从列表推导和生成器表达式中获得类似的“快捷方式”效果。