Skip to content

Instantly share code, notes, and snippets.

@VoQn
Created January 13, 2012 04:41
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save VoQn/1604725 to your computer and use it in GitHub Desktop.
Save VoQn/1604725 to your computer and use it in GitHub Desktop.
Applicative Style Parsec
import Control.Applicative hiding ( (<|>) )
import Text.Parsec
-- parse like ruby's String.strip
escSpace parser = spaces *> parser <* spaces
-- parse like "between" in Text.Parsec
close opener parser closer = char opener *> escSpace parser <* char closer
-- Example
-- "while loop data" expression as Functor
data WhileExp = While Cond [Proc] deriving ( Eq, Show )
type Cond = (a -> Bool)
type Proc = (a -> ())
-- "while loop parser"
whileExp = WhileExp <$> ( string "while" *> close '(' cond ')' ) <*> close '{' body '}'
@VoQn
Copy link
Author

VoQn commented Aug 19, 2014

今だったら Text.Parsec.Token 使ってこう書けるね

Parser.hs (do block Style)

do 文でやるとこう

-- Parser.hs
import Text.Parsec

import Syntax
import Lexer

-- syntax:> "while (condition) { body }"
parseWhile :: Parser Expr
parseWhile = do
  reserved "while" -- Parser () なので何も返らない
  condition <- parens $ parseCond -- (Parser Cond) 型だけど、欲しいのは Cond 型の値の中身
  statements <- braces $ body -- (Parser [Expr]) 型、こちらも [Expr] の中身が必要
  return $ While condition statement

Parser.hs (Applicative Style)

Applicative Style を取った方が「要はこういうことの結果をまとめてしまいたい」が表現しやすい
A a , B b , C c な型から a, b, c 型を取り出して、T a b c な型コンストラクタに渡したい時によく使う

import Control.Applicative ((<$>, (*>), (<*), (<*>))
import Text.Parsec

import Syntax
import Lexer

-- syntax:> "while (condition) { body }"
parseWhile :: Parser Expr
parseWhile = resereved "while" >> While <$> parens cond <*> braces body

話の流れで要るやつ

Syntax.hs

-- Syntax.hs
type Cond = (a -> Bool)

data Expr = Number Int
     -- ...
     <|> While Cond [Expr]
     -- ...

Lexer.hs

-- Lexer.hs
import Text.Parsec
import Text.Parsec.Language (emptyDef)
import qualified Text.Parsec.Token as Token

lexer = Token.makeTokenParser syntaxBases
  where
  syntaxBases = emptyDef  {
       Token.commentLine = "//"
     , Token.reservedOpNames = ["+", "-", "*", "/", "!", "&&", "||", "<", ">", "=="]
     , Token.reservedNames = ["def", "return", "if", "while", "for"]
   }

-- parse "( )"
parens :: Parser a -> Parser a
parens = Token.parens lexer

-- parse "{ }"
braces :: Parser a -> Parser a
braces  = Token.braces lexer

reserved :: String -> Parser ()
reserved = Token.reserved lexer

reservedOp :: String -> Parser ()
reservedOp = Token.reservedOp lexer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment