gimmesilver's blog

Agbird.egloos.com

포토로그



Haskell GUI Programming 하스켈 스프링노트

소개


 Gtk2Hs -  다중 플랫폼 UI 라이브러리인 GTK를 하스켈로 포팅한 버전입니다. Glade와 함께 사용하면 간단한 UI 프로그램을 매우 빠르고 쉽게 개발할 수 있습니다. Glade는 UI layout를 XML 형태로 표현하며 이를 위해 손쉽게 layout을 설계할 수 있는 간단한 편집툴을 제공합니다.


 윈도우용 Glade 다운로드 받는 곳


계산기프로그램 만들기


GtkHs와 Glade 편집툴을 이용해서 만든 간단한 계산기 프로그램입니다.

Parsec.Expr 모듈을 이용하면 EBNF 문법을 거의 그대로 이용해서 파서를 만들 수 있습니다.

exprParser 함수가 바로 그렇게 구현한 파서입니다.

아래 소스는 크게 두 부분으로 나뉩니다.

glade를 이용해서 기술한 UI description file을 읽어서 UI를 만들고 각 버튼 클릭 메시지를 처리하는 등의 GUI 처리 부분이 한 부분이고, GUI를 통해 화면에 출력된 수식을 파싱하여 계산 결과를 처리하는 계산 엔진 부분이 있습니다. 그리고 이 둘은 거의 완벽하게 분리가 가능합니다.


UI용 Glade 소스 - calculator.glade


하스켈 소스

  1. module Calculator where
  2. import Graphics.UI.Gtk
    import Graphics.UI.Gtk.Glade
    import Text.ParserCombinators.Parsec
  3. import Text.ParserCombinators.Parsec.Expr
    import Data.IORef
  4. buttons = [("button0", "0"), ("button1", "1"), ("button2", "2"), ("button3", "3"), ("button4", "4"),
  5.  ("button5", "5"), ("button6", "6"), ("button7", "7"), ("button8", "8"), ("button9", "9"),
  6.  ("button_add", "+"), ("button_sub", "-"), ("button_times", "*"), ("button_div", "/") ]
  7. main = do
        initGUI
        state <- newIORef True -- True: clear previous value
        Just xml <- xmlNew "calculator.glade"
        window <- xmlGetWidget xml castToWindow "window1"
        field <- xmlGetWidget xml castToEntry "entry1"
        result <- xmlGetWidget xml castToButton "button_result"
        onDestroy window mainQuit
        mapM_ (\(widgetName,text) -> do
            widget <- xmlGetWidget xml castToButton widgetName
            onClicked widget $ do
                clear <- readIORef state
                prev <- (\clear -> if (clear)
                    then writeIORef state False >> return ""
                    else get field entryText >>= return) =<< readIORef state
                entrySetText field (prev ++ text)
            ) buttons
        onClicked result $ do
            expr <- get field entryText
            case (parse exprParser "" expr) of
                Left err -> entrySetText field "0"
                Right ret -> entrySetText field $ show ret
            writeIORef state True
        widgetShowAll window
        mainGUI

  8. exprParser :: Parser Float
  9. exprParser = buildExpressionParser table factor
            <?> "expression"
           
    table = [[op "*" (*) AssocLeft, op "/" (/) AssocLeft]
            ,[op "+" (+) AssocLeft, op "-" (-) AssocLeft]
  10.         ]
            where
                op s f assoc
                    = Infix (do {string s; return f}) assoc
                   
    factor = do { char '('
                ; x <- exprParser
                ; char ')'
                ; return x
                }
            <|> number
            <?> "simple expression"
           
    number :: Parser Float
    number = do { ds <- many1 digit
                ; return (read ds) }
             <?> "number"


덧글

댓글 입력 영역