문제

Ruby 1.8에서는 한편으로는 proc/lambda 사이에 미묘한 차이가 있습니다. Proc.new 다른 한편으로는.

  • 그 차이점은 무엇입니까?
  • 어느 것을 선택할지 결정하는 방법에 대한 지침을 제공할 수 있습니까?
  • Ruby 1.9에서는 proc과 람다가 다릅니다.무슨 일이야?
도움이 되었습니까?

해결책

다음으로 생성된 프로세스 간의 또 다른 중요하지만 미묘한 차이점은 다음과 같습니다. lambda 및 다음으로 생성된 프로세스 Proc.new 그들이 처리하는 방법입니다 return 성명:

  • 안에 lambda-생성된 프로세스, return 명령문은 proc 자체에서만 반환됩니다.
  • 안에 Proc.new-생성된 프로세스, return 진술은 좀 더 놀랍습니다.proc뿐만 아니라 제어권도 반환합니다. 뿐만 아니라 proc을 포함하는 메서드에서도 마찬가지입니다!

여기 lambda-생성된 프로시저 return 행동 중.아마도 예상하는 방식으로 작동합니다.

def whowouldwin

  mylambda = lambda {return "Freddy"}
  mylambda.call

  # mylambda gets called and returns "Freddy", and execution
  # continues on the next line

  return "Jason"

end


whowouldwin
#=> "Jason"

이제 여기에 Proc.new-생성된 프로시저 return 같은 일을하고 있습니다.이제 여러분은 Ruby가 매우 자랑스러워하는 최소 놀라움의 원칙을 깨뜨린 사례 중 하나를 보게 될 것입니다.

def whowouldwin2

  myproc = Proc.new {return "Freddy"}
  myproc.call

  # myproc gets called and returns "Freddy", 
  # but also returns control from whowhouldwin2!
  # The line below *never* gets executed.

  return "Jason"

end


whowouldwin2         
#=> "Freddy"

이 놀라운 동작 덕분에(타이핑 횟수도 줄고) 저는 다음을 선호하는 경향이 있습니다. lambda ~ 위에 Proc.new 프록을 만들 때.

다른 팁

추가 설명을 제공하려면 다음을 수행하십시오.

Joey는 다음의 반환 동작을 말합니다. Proc.new 놀랍습니다.그러나 Proc.new가 블록처럼 동작한다는 점을 고려하면 이것이 바로 블록이 동작하는 방식이기 때문에 이는 놀라운 일이 아닙니다.반면에 람바는 메소드처럼 행동합니다.

이는 실제로 인수 개수(인수 수)와 관련하여 Procs가 유연한 반면 람다는 그렇지 않은 이유를 설명합니다.블록은 모든 인수를 제공할 것을 요구하지 않지만 메소드는 제공합니다(기본값이 제공되지 않는 한).람다 인수 기본값을 제공하는 것은 Ruby 1.8에서는 옵션이 아니지만 이제 대체 람다 구문을 사용하여 Ruby 1.9에서 지원됩니다(webmat에서 언급한 대로).

concat = ->(a, b=2){ "#{a}#{b}" }
concat.call(4,5) # => "45"
concat.call(1)   # => "12"

그리고 Michiel de Mare(OP)는 Ruby 1.9에서 Procs와 람다가 arity와 동일하게 동작한다는 점에 대해 올바르지 않습니다.위에 지정된 대로 1.8의 동작을 여전히 유지하고 있음을 확인했습니다.

break 명령문은 Procs나 람다에서 실제로 의미가 없습니다.Procs에서는 휴식이 이미 완료된 Proc.new에서 반환됩니다.그리고 람다에서 벗어나는 것은 본질적으로 메서드이고 메서드의 최상위 수준에서는 결코 중단되지 않기 때문에 의미가 없습니다.

next, redo, 그리고 raise Procs와 람다 모두에서 동일하게 동작합니다.반면 retry 어느 쪽에서도 허용되지 않으며 예외가 발생합니다.

그리고 마지막으로, proc 일관성이 없고 예기치 않은 동작이 있으므로 메서드를 사용해서는 안 됩니다.Ruby 1.8에서는 실제로 람다를 반환합니다!Ruby 1.9에서는 이 문제가 수정되어 Proc를 반환합니다.Proc을 생성하려면 다음을 따르십시오. Proc.new.

더 많은 정보를 원하시면 O'Reilly's를 적극 추천합니다. Ruby 프로그래밍 언어 이것이 대부분의 정보에 대한 나의 출처입니다.

나는 찾았다 이 페이지 이는 차이점이 무엇인지 보여줍니다. Proc.new 그리고 lambda 이다.페이지에 따르면 유일한 차이점은 람다가 허용하는 인수 수에 대해 엄격하다는 것입니다. Proc.new 누락된 인수를 다음으로 변환합니다. nil.다음은 차이점을 보여주는 IRB 세션의 예입니다.

irb(main):001:0> l = lambda { |x, y| x + y }
=> #<Proc:0x00007fc605ec0748@(irb):1>
irb(main):002:0> p = Proc.new { |x, y| x + y }
=> #<Proc:0x00007fc605ea8698@(irb):2>
irb(main):003:0> l.call "hello", "world"
=> "helloworld"
irb(main):004:0> p.call "hello", "world"
=> "helloworld"
irb(main):005:0> l.call "hello"
ArgumentError: wrong number of arguments (1 for 2)
    from (irb):1
    from (irb):5:in `call'
    from (irb):5
    from :0
irb(main):006:0> p.call "hello"
TypeError: can't convert nil into String
    from (irb):2:in `+'
    from (irb):2
    from (irb):6:in `call'
    from (irb):6
    from :0

또한 이 페이지에서는 오류 허용 동작을 특별히 원하지 않는 한 람다 사용을 권장합니다.나는 이 감정에 동의한다.람다를 사용하는 것이 좀 더 간결해 보이고, 차이가 미미하므로 평균적인 상황에서는 더 나은 선택인 것 같습니다.

Ruby 1.9에 대해서는 죄송합니다. 아직 1.9를 살펴보지는 않았지만 그렇게 많이 바뀔 것이라고는 생각하지 않습니다. (내 말을 믿지 마세요. 몇 가지 변경 사항에 대해 들어보신 것 같으니, 나는 아마도 틀렸을 것입니다).

Proc은 더 오래되었지만 return의 의미는 다음과 같은 이유로 나에게 매우 직관에 반합니다(적어도 내가 언어를 배울 때).

  1. proc을 사용하고 있다면 일종의 기능적 패러다임을 사용하고 있을 가능성이 높습니다.
  2. Proc는 기본적으로 goto이고 본질적으로 매우 비기능적인 범위(이전 응답 참조) 밖으로 돌아올 수 있습니다.

Lambda는 기능적으로 더 안전하고 추론하기 쉽습니다. 저는 항상 proc 대신 Lambda를 사용합니다.

미묘한 차이에 대해서는 많이 말할 수 없습니다.하지만 이제 Ruby 1.9에서는 람다와 블록에 대한 선택적 매개변수를 허용한다는 점을 지적할 수 있습니다.

1.9 미만의 안정적인 람다에 대한 새로운 구문은 다음과 같습니다.

stabby = ->(msg='inside the stabby lambda') { puts msg }

Ruby 1.8에는 해당 구문이 없었습니다.블록/람다를 선언하는 기존 방법도 선택적 인수를 지원하지 않았습니다.

# under 1.8
l = lambda { |msg = 'inside the stabby lambda'|  puts msg }
SyntaxError: compile error
(irb):1: syntax error, unexpected '=', expecting tCOLON2 or '[' or '.'
l = lambda { |msg = 'inside the stabby lambda'|  puts msg }

그러나 Ruby 1.9는 이전 구문에서도 선택적 인수를 지원합니다.

l = lambda { |msg = 'inside the regular lambda'|  puts msg }
#=> #<Proc:0x0e5dbc@(irb):1 (lambda)>
l.call
#=> inside the regular lambda
l.call('jeez')
#=> jeez

Leopard 또는 Linux용 Ruby1.9를 구축하고 싶다면 다음을 확인하세요. 이 기사 (뻔뻔한 자기 홍보).

짧은 답변:중요한 것은 무엇인가 return 하다:람다는 자체적으로 반환하고, proc은 자체적으로 반환하고 이를 호출한 함수를 반환합니다.

덜 명확한 것은 각각을 사용하려는 이유입니다.람다는 함수형 프로그래밍 측면에서 우리가 기대하는 것입니다.기본적으로 현재 범위가 자동으로 바인딩되는 익명 메서드입니다.둘 중 아마도 람다(lambda)를 사용해야 할 것입니다.

반면에 Proc은 언어 자체를 구현하는 데 정말 유용합니다.예를 들어 "if" 문이나 "for" 루프를 구현할 수 있습니다.proc에서 발견된 모든 반환은 "if" 문뿐만 아니라 이를 호출한 메서드에서 반환됩니다.이것이 언어가 작동하는 방식, "if" 문이 작동하는 방식입니다. 따라서 내 추측으로는 Ruby가 이것을 은밀히 사용하고 강력해 보였기 때문에 노출했을 뿐입니다.

루프, if-else 구문 등과 같은 새로운 언어 구문을 만드는 경우에만 이것이 필요합니다.

이를 확인하는 좋은 방법은 람다가 자체 범위(메서드 호출인 것처럼)에서 실행되는 반면 Procs는 호출 메서드와 함께 인라인으로 실행되는 것으로 볼 수 있다는 것입니다. 적어도 어느 것을 사용할지 결정하는 좋은 방법입니다. 각각의 경우에.

더 이상 사용되지 않지만 1.8과 1.9에서는 다르게 처리되는 질문의 세 번째 방법인 "proc"에 대한 설명을 보지 못했습니다.

다음은 세 가지 유사한 호출 간의 차이점을 쉽게 확인할 수 있는 상당히 자세한 예입니다.

def meth1
  puts "method start"

  pr = lambda { return }
  pr.call

  puts "method end"  
end

def meth2
  puts "method start"

  pr = Proc.new { return }
  pr.call

  puts "method end"  
end

def meth3
  puts "method start"

  pr = proc { return }
  pr.call

  puts "method end"  
end

puts "Using lambda"
meth1
puts "--------"
puts "using Proc.new"
meth2
puts "--------"
puts "using proc"
meth3

Ruby의 클로저 Ruby에서 블록, 람다, 프로세스가 어떻게 작동하는지에 대한 좋은 개요입니다.

람다는 다른 언어와 마찬가지로 예상대로 작동합니다.

유선 Proc.new 놀랍고 혼란스럽습니다.

그만큼 return 다음에 의해 생성된 proc의 명령문 Proc.new 그 자체로 제어권을 반환할 뿐만 아니라 또한 그것을 둘러싸는 메소드로부터.

def some_method
  myproc = Proc.new {return "End."}
  myproc.call

  # Any code below will not get executed!
  # ...
end

당신은 이렇게 주장할 수 있다 Proc.new block과 마찬가지로 바깥쪽 메서드에 코드를 삽입합니다.하지만 Proc.new 객체를 생성하는 반면 블록은 부분의 객체.

그리고 람다와 람다 사이에는 또 다른 차이점이 있습니다. Proc.new, 이는 (잘못된) 인수를 처리하는 것입니다.람다가 그것에 대해 불평하는 동안 Proc.new 추가 인수를 무시하거나 인수가 없으면 nil로 간주합니다.

irb(main):021:0> l = -> (x) { x.to_s }
=> #<Proc:0x8b63750@(irb):21 (lambda)>
irb(main):022:0> p = Proc.new { |x| x.to_s}
=> #<Proc:0x8b59494@(irb):22>
irb(main):025:0> l.call
ArgumentError: wrong number of arguments (0 for 1)
        from (irb):21:in `block in irb_binding'
        from (irb):25:in `call'
        from (irb):25
        from /usr/bin/irb:11:in `<main>'
irb(main):026:0> p.call
=> ""
irb(main):049:0> l.call 1, 2
ArgumentError: wrong number of arguments (2 for 1)
        from (irb):47:in `block in irb_binding'
        from (irb):49:in `call'
        from (irb):49
        from /usr/bin/irb:11:in `<main>'
irb(main):050:0> p.call 1, 2
=> "1"

그런데, proc Ruby 1.8에서는 람다를 생성하지만 Ruby 1.9+에서는 다음과 같이 동작합니다. Proc.new, 정말 혼란스럽습니다.

Accordion Guy의 답변을 자세히 설명하려면 다음을 수행하세요.

그것을주의해라 Proc.new 블록을 전달하여 proc을 생성합니다.나는 그것을 믿는다 lambda {...} 블록을 전달하는 메서드 호출이 아닌 일종의 리터럴로 구문 분석됩니다. return메서드 호출에 연결된 블록 내부에서 호출하면 블록이 아닌 메서드에서 반환되며 Proc.new 사례는 이에 대한 예입니다.

(1.8입니다.이것이 1.9로 어떻게 해석되는지 모르겠습니다.)

나는 이것에 대해 조금 늦었습니다. 그러나 한 가지 훌륭하지만 거의 알려지지 않은 것이 있습니다. Proc.new 댓글에는 전혀 언급되지 않았습니다.다음과 같이 선적 서류 비치:

Proc::new 연결된 블록이 있는 메서드 내에서만 블록 없이 호출될 수 있습니다. 블록이 다음으로 변환됩니다. Proc 물체.

즉, Proc.new 연쇄 산출 방법을 허용합니다:

def m1
  yield 'Finally!' if block_given?
end

def m2
  m1 &Proc.new
end

m2 { |e| puts e } 
#⇒ Finally!

와의 행동의 차이 return IMHO는 2의 가장 중요한 차이점입니다.나는 또한 Proc.new보다 타이핑이 적기 때문에 람다를 선호합니다 :-)

그것을 강조할 가치가 있다 return proc에서는 어휘적으로 둘러싸는 메서드에서 반환됩니다. 즉, proc이 생성된 메서드, ~ 아니다 proc을 호출한 메서드입니다.이는 procs의 폐쇄 속성으로 인한 결과입니다.따라서 다음 코드는 아무것도 출력하지 않습니다.

def foo
  proc = Proc.new{return}
  foobar(proc)
  puts 'foo'
end

def foobar(proc)
  proc.call
  puts 'foobar'
end

foo

proc은 다음에서 실행되지만 foobar, 다음에서 생성되었습니다. foo 그래서 return 출구 foo, 뿐만 아니라 foobar.Charles Caldwell이 위에서 쓴 것처럼 GOTO 느낌이 듭니다.내 생각에는, return 어휘적 컨텍스트에서 실행되는 블록에서는 괜찮지만, 다른 컨텍스트에서 실행되는 proc에서 사용되면 훨씬 덜 직관적입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top