Haskell에서 Ruby 사용 - 메소드 호출

9122 단어 루비하스켈
Haskell의 값을 Ruby의 값으로 변환하거나 Haskell에서 Ruby의 메소드를 호출하는 방법을 소개합니다.

도서관 - hruby



hruby이라는 라이브러리를 사용합니다.

라이브러리 내부에서는 ruby.h 를 사용해 FFI로 Ruby를 호출하고 있는 느낌입니다. ( ruby 명령을 두드리는 느낌이 아닐 것 같습니다)

Haskell의 Int를 Ruby 값으로 설정



Haskell 1을 Ruby 값으로 만드는 예제입니다.
import Foreign.Ruby

main :: IO ()
main = do
    ri <- startRubyInterpreter
    Right rubyOne <- toRuby ri (1 :: Int)
    print rubyOne
    closeRubyInterpreter ri
riRubyInterpreter 유형의 변수입니다.

출력



출력은 이런 느낌이 되었습니다
0x0000000000000003

Ruby의 값을 Haskell의 값으로 설정


import Foreign.Ruby

main :: IO ()
main = do
    ri <- startRubyInterpreter

    -- Haskell => Ruby
    Right rubyOne <- toRuby ri (1 :: Int)
    print rubyOne

    -- Ruby => Haskell
    Right haskellOne <- fromRuby ri rubyOne :: IO (Either RubyError Int)
    putStr "Ruby => Haskell:"
    print haskellOne

    closeRubyInterpreter ri      

주의


:: IO (Either RubyError Int) 없으면 Haskell의 어떤 유형으로 변환해야할지 모르기 때문에 필수입니다.

출력



출력은 이런 느낌이
0x0000000000000003
Ruby => Haskell:1

withRubyInterpreter 사용


startRubyInterpretercloseRubyInterpreter를 보면 정신적으로 좋지 않기 때문에 대출 패턴 withRubyInterpreter을 사용하는 방법을 소개합니다.

사용법은 다음과 같은 느낌입니다.
import Foreign.Ruby

main :: IO ()
main = do
    withRubyInterpreter $ \ri -> do
        Right rubyOne <- toRuby ri (1 :: Int)
        print rubyOne

object allocation during garbage collection phase (미해결)



다음과 같이 RubyInterpreter를 여러 번 작성하면 "ruby: [BUG] object allocation during garbage collection phase"라는 오류가 발생합니다. 그래서 함수 마다 내부에 withRubyInterpreter 를 사용해, 그것들을 복수회 부르면 떨어져 버리므로, 하나의 RubyInterpreter 밖에 만들 수 없는 느낌입니다.
import Foreign.Ruby

main :: IO ()
main = do
    withRubyInterpreter $ \ri -> do
        Right rubyOne <- toRuby ri (1 :: Int)
        print rubyOne

    withRubyInterpreter $ \ri -> do
        Right rubyOne <- toRuby ri (1 :: Int)
        print rubyOne



그래서 지금은 RubyInterpretermain 로 생성해, 다른 함수에는 인수에 건네주고 대처하고 있습니다.

메서드 호출



다음 예제는 Ruby [5, -3, 93, -73, 2] * 3를 Haskell에서 수행하는 예제입니다.
mySafeMethodCall 라는 것은, 자작 함수로 메소드를 호출하는 라이브러리의 메소드를 호출하는 함수로 잘 호출할 수 없었기 때문에, Foreign.Ruby.Bindings 에 있는 함수들을 조합해 만든 것입니다.
import Foreign.Ruby
import Foreign.Ruby.Bindings

mySafeMethodCall :: RubyInterpreter
    -> RValue
    -> String
    -> [RValue]
    ->  IO (Either RubyError RValue)
mySafeMethodCall ri reciever methodName args = makeSafe ri $ do
    rid <- rb_intern methodName
    rb_funcall reciever rid args

main :: IO ()
main = do
    withRubyInterpreter $ \ri -> do
        -- Haskell => Ruby
        Right rubyArr   <- toRuby ri ([5, -3, 93, -73, 2] :: [Int])
        Right rubyThree <- toRuby ri (3 :: Int)

        -- call Array#*
        Right rubyTimesed  <- mySafeMethodCall ri rubyArr "*" [rubyThree]

        putStr "rubyArr * 3: "
        Right haskellTimesedArr <- fromRuby ri rubyTimesed :: IO (Either RubyError [Int])
        print haskellTimesedArr
"*"는 메소드 이름입니다. Ruby에서는 연산자도 메소드이므로 이것으로 OK입니다. 연산자에 한정하지 않고, 메소드명을 걸면 움직입니다

출력



올바르게 출력할 수 있음을 알 수 있습니다.
rubyArr * 3: [5,-3,93,-73,2,5,-3,93,-73,2,5,-3,93,-73,2]

GitHub 리포지토리



hruby 사용법을 이해하는 데 사용한 저장소가 있는 곳입니다.

좋은 웹페이지 즐겨찾기