Programming

루비에서 proc와 람다의 차이점은 무엇입니까?

procodes 2020. 5. 26. 21:28
반응형

루비에서 proc와 람다의 차이점은 무엇입니까?


그리고 언제 다른 것을 사용하지 않습니까?


한 가지 차이점은 인수를 처리하는 방식에 있습니다. 사용 PROC 만들기 proc {}Proc.new {}동일합니다. 그러나를 사용 lambda {}하면 전달 된 인수 수를 확인하는 proc이 제공됩니다. 보낸 사람 ri Kernel#lambda:

상당 Proc.new 결과 PROC 제외하고는 호출시에 전달 된 파라미터의 개수를 확인 개체.

예를 들면 :

p = Proc.new {|a, b| puts a**2+b**2 } # => #<Proc:0x3c7d28@(irb):1>
p.call 1, 2 # => 5
p.call 1 # => NoMethodError: undefined method `**' for nil:NilClass
p.call 1, 2, 3 # => 5
l = lambda {|a, b| puts a**2+b**2 } # => #<Proc:0x15016c@(irb):5 (lambda)>
l.call 1, 2 # => 5
l.call 1 # => ArgumentError: wrong number of arguments (1 for 2)
l.call 1, 2, 3 # => ArgumentError: wrong number of arguments (3 for 2)

또한 Ken이 지적한 것처럼 return람다 내부를 사용 하면 해당 람다의 값이 반환되지만 returnproc에 사용 하면 둘러싸는 블록에서 반환됩니다.

lambda { return :foo }.call # => :foo
return # => LocalJumpError: unexpected return
Proc.new { return :foo }.call # => LocalJumpError: unexpected return

따라서 대부분의 빠른 사용법은 동일하지만 자동 엄격한 인수 검사 (때로는 디버깅에 도움이 될 수 있음)를 원하거나 return명령문을 사용하여 proc 값을 반환 해야하는 경우을 사용하십시오 lambda.


procs와 lambdas의 실제 차이점은 제어 흐름 키워드와 관련이 있습니다. 나는에 대해 이야기하고 return, raise, break, redo, retry그 제어 워드 - 등. proc에 return 문이 있다고 가정 해 봅시다. proc을 호출하면 proc을 덤프 할뿐만 아니라 다음과 같은 엔 클로징 메소드에서 돌아옵니다.

def my_method
  puts "before proc"
  my_proc = Proc.new do
    puts "inside proc"
    return
  end
  my_proc.call
  puts "after proc"
end

my_method

shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc

puts우리가 proc을 호출했을 때 return메소드 내에서 우리를 메소드에서 버렸기 때문에 메소드 의 마지막 은 실행되지 않았습니다 . 그러나 proc을 람다로 변환하면 다음과 같은 결과가 나타납니다.

def my_method
  puts "before proc"
  my_proc = lambda do
    puts "inside proc"
    return
  end
  my_proc.call
  puts "after proc"
end

my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc

람다 내 리턴은 람다 자체에서 우리를 덤프하고 엔 클로징 메소드는 계속 실행됩니다. 제어 흐름 키워드가 procs와 람다 내에서 처리되는 방식은 주요 차이점입니다.


두 가지 주요 차이점 만 있습니다.

  • 먼저 a lambda는 전달 된 인수 수를 확인하지만 a proc는 그렇지 않습니다. lambda, 잘못된 수의 인수를 전달하면 오류가 발생하지만 proc예기치 않은 인수는 무시하고 nil누락 된 인수를 지정 합니다.
  • 둘째, lambda반환 할 때 제어를 호출 메서드로 다시 전달합니다. proc반환 할 때 호출 방법 등을 거치지 않고, 그래서 즉시 않습니다.

이것이 어떻게 작동하는지 보려면 아래 코드를 살펴보십시오. 우리의 첫 번째 방법은 proc; 두 번째는 a를 호출합니다 lambda.

def batman_ironman_proc
  victor = Proc.new { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

puts batman_ironman_proc # prints "Batman will win!"

def batman_ironman_lambda
  victor = lambda { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

puts batman_ironman_lambda # prints "Iron Man will win!"

proc"배트맨이 이길 것입니다!" 라는 말을 참조하십시오 . 이것은 batman_ironman_proc 메소드로 돌아 가지 않고 즉시 리턴되기 때문입니다.

lambda그러나 우리 는 호출 된 후에 메소드로 되돌아가므로 메소드는 "아이언 맨이 이길 것입니다!"


일반적으로 람다는 방법과 비슷하기 때문에 proc보다 직관적입니다. 그들은 arity에 대해 매우 엄격하며 return을 호출하면 종료됩니다. 이런 이유로, 많은 루비 스트들은 람다가 procs의 특정 기능을 필요로하지 않는 한 가장 먼저 선택합니다.

Procs: Objects of class Proc . Like blocks, they are evaluated in the scope where they’re defined. Lambdas: Also objects of class Proc but subtly different from regular procs. They’re closures like blocks and procs, and as such they’re evaluated in the scope where they’re defined.

Creating Proc

a = Proc.new { |x| x 2 }

Creating lambda

b = lambda { |x| x 2 }


Here is another way to understand this.

A block is a chunk of code attached to the invocation to a call of a method on an object. In the below example, self is an instance of an anonymous class inheriting from ActionView::Base in the Rails framework (which itself includes many helper modules). card is a method we call on self. We pass in an argument to the method and then we always attach the block to the end of the method invocation:

self.card :contacts do |c|
  // a chunk of valid ruby code    
end

Ok, so we are passing a chunk of code to a method. But how do we make use of this block? One option is to convert the chunk of code into an object. Ruby offers three ways to convert a chunk of code into an object

# lambda
> l = lambda { |a| a + 1 }
> l.call(1)
=> 2 

# Proc.new
> l2= Proc.new { |a| a + 1 }
> l2.call(1)
=> 2 

# & as the last method argument with a local variable name
def add(&block)
end

In the method above, the & converts the block passed to the method into an object and stores that object in the local variable block. In fact, we can show that it has the same behavior as lambda and Proc.new:

def add(&block)
  block
end

l3 = add { |a| a + 1 }
l3.call(1)
=> 2

This is IMPORTANT. When you pass a block to a method and convert it using &, the object it creates uses Proc.new to do the conversion.

Note that I avoided the use of "proc" as an option. That's because it Ruby 1.8, it is the same as lambda and in Ruby 1.9, it is the same as Proc.new and in all Ruby versions it should be avoided.

So then you ask what is the difference between lambda and Proc.new?

First, in terms of parameter passing, lambda behaves like a method call. It will raise an exception if you pass the wrong number of arguments. In contrast, Proc.new behaves like parallel assignment. All unused arguments get converted into nil:

> l = lambda {|a,b| puts "#{a} + #{b}" }
 => #<Proc:0x007fbffcb47e40@(irb):19 (lambda)> 
> l.call(1)
ArgumentError: wrong number of arguments (1 for 2)

> l2 = Proc.new {|a,b| puts "#{a} + #{b}" }
=> #<Proc:0x007fbffcb261a0@(irb):21> 
> l2.call(1)
1 + 

Second, lambda and Proc.new handle the return keyword differently. When you do a return inside of Proc.new, it actually returns from the enclosing method, that is, the surrounding context. When you return from a lambda block, it just returns from the block, not the enclosing method. Basically, it exits from the call to the block and continues execution with the rest of the enclosing method.

> def add(a,b)
  l = Proc.new { return a + b}
  l.call
  puts "now exiting method"
end
> add(1,1)
=> 2  # NOTICE it never prints the message "now exiting method"

> def add(a,b)
  l = lambda { return a + b }
  l.call
  puts "now exiting method"
end
> add(1,1)
=> now exiting method  # NOTICE this time it prints the message "now exiting method"

So why this behavioral difference? The reason is because with Proc.new, we can use iterators inside the context of enclosing methods and draw logical conclusions. Look at this example:

> def print(max)
  [1,2,3,4,5].each do |val|
    puts val
    return if val > max
  end
end
> print(3)
1
2
3
4

We expect that when we invoke return inside the iterator, it will return from the enclosing method. Remember the blocks passed to iterators get converted to objects using Proc.new and that is why when we use return, it will exit the enclosing method.

You can think of lambdas as anonymous methods, they isolate individual blocks of code into an object that can be treated like a method. Ultimately, think of a lambda as behaving as an anomyous method and Proc.new behaving as inline code.


# Proc Examples

p = Proc.new { |x| puts x*2 }
[1,2,3].each(&p)              # The '&' tells ruby to turn the proc into a block 

proc = Proc.new { puts "Hello World" }
proc.call

# Lambda Examples

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           

Differences between Procs and Lambdas

Before I get into the differences between procs and lambdas, it is important to mention that they are both Proc objects.

proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }

proc.class # returns 'Proc'
lam.class  # returns 'Proc'

However, lambdas are a different ‘flavor’ of procs. This slight difference is shown when returning the objects.

proc   # returns '#<Proc:0x007f96b1032d30@(irb):75>'
lam    # returns '<Proc:0x007f96b1b41938@(irb):76 (lambda)>'

1. Lambdas check the number of arguments, while procs do not

lam = lambda { |x| puts x }    # creates a lambda that takes 1 argument
lam.call(2)                    # prints out 2
lam.call                       # ArgumentError: wrong number of arguments (0 for 1)
lam.call(1,2,3)                # ArgumentError: wrong number of arguments (3 for 1)

In contrast, procs don’t care if they are passed the wrong number of arguments.

proc = Proc.new { |x| puts x } # creates a proc that takes 1 argument
proc.call(2)                   # prints out 2
proc.call                      # returns nil
proc.call(1,2,3)               # prints out 1 and forgets about the extra arguments

2. Lambdas and procs treat the ‘return’ keyword differently

‘return’ inside of a lambda triggers the code right outside of the lambda code

def lambda_test
  lam = lambda { return }
  lam.call
  puts "Hello world"
end

lambda_test                 # calling lambda_test prints 'Hello World'

‘return’ inside of a proc triggers the code outside of the method where the proc is being executed

def proc_test
  proc = Proc.new { return }
  proc.call
  puts "Hello world"
end

proc_test                 # calling proc_test prints nothing

And to answer your other query, which one to use and when ? I'll follow @jtbandes as he has mentioned

So for most quick uses they're the same, but if you want automatic strict argument checking (which can also sometimes help with debugging), or if you need to use the return statement to return the value of the proc, use lambda.

Originally posted here


A helpful post on ruby guides: blocks, procs & lambdas

Procs return from the current method, while lambdas return from the lambda itself.

Procs don’t care about the correct number of arguments, while lambdas will raise an exception.


the differences between proc and lambda is that proc is just a copy of code with arguments replaced in turn, while lambda is a function like in other languages. (behavior of return, arguments checks)

참고URL : https://stackoverflow.com/questions/1740046/whats-the-difference-between-a-proc-and-a-lambda-in-ruby

반응형