ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • What is Ruby Proc??
    Ruby 2016. 10. 29. 00:39

    [참고]




    Proc(절차, Procedure) 객체 이해하기 

    루비에서는 Proc 클래스를 통해서 익명 함수를 생성할 수 있다. Proc는 Procedure의 줄임말로 어떤 처리 과정(절차)를 담고있다는 의미이다. Proc 또한 일반 루비 클래스와 다르지 않아 new 메서드를 통해 생성이 가능하다

    Proc.new

    Proc.new 메서드는 블록을 통해서 절차(루비 표현식들)를 넘겨받는다.

    Proc.new do
         puts 'Hello, world!'
    end

    Proc.new는 Proc 객체를 반환한다. 이 생성자 메서드는 넘겨받은 익명 함수에 대해서 어떠한 일도 하지 않고, 익명 함수를 그대로 저장한다. 따라서 블록에 쓰여진 루비 표현식은 실행되지 않는다.



    Proc 객체 실행하기

    Proc 객체는 원하는 시점에 언제라도 실행이 가능하다. 아래 코드는 Proc 객체를 변수에 대입하고 실행하는 예제이다. Proc의 실행은 크게 3가지 방법이 있다. .call() 메서드 호출이 가능하며 .() .[ ] 호출이 가능하다.

    p = Proc.new { puts 'Hello, world!' }

    p.call()          # => Hello, world!

    p.()               # => Hello, world!

    p.[ ]              # => Hello, world!

    형태는 다르지만 모두 같은 방식으로 동작한다.


    루비의 Proc 객체는 자바스크립트의 함수 호출방법이 다르다. 파이썬이나 자바스크립트에서는 함수 이름으로 접근하면 함수 자체에 접근할 수 있고 직접 호출이 가능하지만 루비에서는 불가능하다. 



    블록 

    블록은 엄밀히 말하면 Proc 객체가 아니다. 단, 메서드 선언시에 & 연산자를 통해서 블록을 명시적으로 Proc 객체로 받아올 수 있다.

    def hello(&b)
         b.call()
    end

    hello do
         puts 'Hello, world!
    end

    #Hello, world!


    proc 

    Kernal#proc 메서드 또한 Proc.new 와 같다.

    p = proc { puts 'Hello, world!' }
    p.call()
    #Hello, world!



    Proc 객체와 람다(lambda)

    루비는 lambda 라고 하는 Proc 객체 생성하는 방법이 존재한다. 

    l = lambda ( puts 'Hello, world!' }

    l.class           # => Proc
    l.call()          # => Hello, world!


    lambda는 왜 존재하는 것일까? 람다라는 표현을 거슬러 올라가면 람다 대수가 나온다. 람다 대수는 알론조 처치에 의해 만들어진 수학 체계이다. 이 체계가 흥미로운 것은 하나의 인자를 받는 함수들만을 사용하면서, 튜링 컴플리트하다는 점이다. 즉 완전히 수작적이면서 튜링 머신에서 가능한 모든 계산이 가능하다는 의미이다. 단, 여기서 lambda 라는 표현은 엄밀한 의미에서 수학적인 표현이라기보다는 루비 이전의 언어들에서 익명 함수를 의미할 때 사용해오던 관용구라고 이해나느 것이 좋다. 



    Proc#lambda? 를 사용한 lambda 여부 확인 

    Proc 객체와 lambda 로 만들어진 객체를 구분하는 방법은 Proc 객체의 lambda? 메서드로 확인이 기능하다.


    Proc.new().lambda?           #=> false
    proc{}.lambda?          #=> false
    lambda{}.lambda?     #=> true
    ->{}.lamgda?          # => true

    일반적인 메서드를 객체화해서 Proc 객체로 변환하면 lambda Proc 객체가 된다.

    def hello; end
    hello_method = method(:hello)
    hello_method.to_proc.lambd? #=> true



    Proc와 lambda 의 return 작동방식의 차이


    def return_two(&p)
         p.call
         return 2
    end

    return_two(&Proc.new {return 1} )
    # => LocalJumpError : unexpected return

    밖에서 Proc 객체를 넘겨받으면 LocalJumpError 예외를 발생시킨다. 이는 return이 어떤 맥락에서 해석되어야 하는지가 불분명하기 때문이다. (Proc 객체? or Proc 객체를 실행하는 문맥)

    다음은 밖에서 넘겨받는 대신 안에서 객체를 생성하는 예제이다.

    def return_two()
         p = Proc.new { return 1 }
         p.call
         return 2
    end

    return_two    
    # => 1 

    이번에는 1을 반환한다. Proc의 Return문이 Return_two의 Return으로 실행되었다.


    lambda 로 만든 Proc 객체를 실행해보자

    def return_two(&p)
         puts. p.call
         return 2
    end

    return_two ( &lambda { return 1 } )
    # 1 
    # => 2

    이번에는 2를 반환했다.  p.call의 반환은 1이 반환된다.  lambda 함수에서 return 문을 사용하면 Proc 객체, 즉 익명 함수 자체의 반환이 된다. 따라서 lambda 함수에서는 1을 반환하고 return_two 에서는 lambda Proc 와 무관하게 2를 반환한다.





    끄읕



    'Ruby ' 카테고리의 다른 글

    Programming Ruby (15) 표현식 - 2  (0) 2016.10.31
    Programming Ruby (14) 표현식 - 1  (0) 2016.10.31
    Programming Ruby (13) 메서드 파헤치기  (0) 2016.10.28
    Programming Ruby (11) 숫자  (0) 2016.10.27
    Programming Ruby(12) 문자열  (0) 2016.10.26
Designed by Tistory.