1 {-# OPTIONS_GHC -fno-warn-unused-do-bind -fno-warn-orphans #-}
2 {-# LANGUAGE OverloadedStrings #-}
6 -- Copyright : Tomáš Musil 2014
9 -- Maintainer : tomik.musil@gmail.com
10 -- Stability : experimental
12 -- Parser for Hindley-Milner terms and types.
20 import Data.Char (isAsciiLower, isAsciiUpper)
21 import Data.Text as T hiding (map)
22 import Data.Attoparsec.Text
23 import Control.Applicative
28 -- >>> import Test.QuickCheck
29 -- >>> import Test.HM.Term
32 -- >>> print $ Lam "x" (Var "x")
37 braced :: String -> String
38 braced t = "(" ++ t ++ ")"
40 instance Show Term where
42 show (Lam x (NTTerm (Lam y t))) = show (Lam (x ++ " " ++ y) t)
43 show (Lam x t) = braced $ "λ" ++ x ++ "." ++ show t
44 show (App a (NTTerm (App b c))) = show a ++ " " ++ braced ( show (App b c))
45 show (App t r) = show t ++ " " ++ show r
46 show (Let x e1 e2) = braced $ "LET " ++ x ++ " = " ++ show e1 ++ " IN " ++ show e2
47 show (Lit (LInt x)) = show x
48 show (Lit (LBool x)) = show x
49 show (Lit (LFunc x)) = show x
51 instance Show TypedTerm where
52 show (NTTerm t) = show t
53 show (TTerm (Var x) tp) = x ++ " :: " ++ show tp
54 show (TTerm t tp) = braced (show t) ++ " :: " ++ show tp
56 instance Show Type where
57 show (Primitive t) = t
59 show (TypeFunction a b) = braced $ show a ++ " -> " ++ show b
61 instance Show TypeScheme where
62 show (TScheme t) = show t
63 show (TSForAll x t) = braced $ "∀" ++ x ++ ": " ++ show t
65 tRead :: String -> TypedTerm
66 tRead s = case parseOnly (parseTypedTerm <* endOfInput) (T.pack s) of
70 parseTerm :: Parser Term
71 parseTerm = parseLet <|>
74 parseBraces parseTerm <|>
78 parseTermNoApp :: Parser Term
79 parseTermNoApp = parseBraces parseTerm <|>
85 parseTypeAndTerm :: Parser Term -> Parser TypedTerm
86 parseTypeAndTerm p = do
90 return $! TTerm term tp
93 parseTypedTermNoApp :: Parser TypedTerm
94 parseTypedTermNoApp = parseBraces parseTypedTerm <|>
95 parseTypeAndTerm parseTermNoApp <|>
96 (NTTerm <$> parseTermNoApp)
98 parseTypedTerm :: Parser TypedTerm
99 parseTypedTerm = parseTypeAndTerm parseTerm <|>
100 (NTTerm <$> parseTerm) <|>
101 parseBraces parseTypedTerm
103 parseType :: Parser Type
104 parseType = parseType <|>
105 parseTypeFunction <|>
109 parsePrimitive :: Parser Type
111 x <- satisfy isAsciiUpper
113 return $! Primitive (x:xs)
115 parseTypeVar :: Parser Type
117 x <- many1 $ satisfy isAsciiLower
120 parseTypeFunction :: Parser Type
121 parseTypeFunction = do
122 a <- parseBraces parseType <|> parsePrimitive <|> parseTypeVar
125 return $! TypeFunction a b
127 parseTypeScheme :: Parser TypeScheme
128 parseTypeScheme = parseBraces parseTypeScheme <|>
130 (TScheme <$> parseType)
132 parseForAll :: Parser TypeScheme
135 (TypeVar x) <- parseTypeVar
138 return $! TSForAll x t
140 parseBraces :: Parser a -> Parser a
147 parseLet :: Parser Term
155 return $! Let x e1 e2
157 parseVar :: Parser Term
159 x <- many1 $ satisfy isAsciiLower
162 parseLit :: Parser Term
164 x <- parseLInt <|> parseLBool <|> parseLFun
167 parseLFun :: Parser Literal
169 (string "If" >> return (LFunc If))
171 parseLBool :: Parser Literal
173 (string "True" >> return (LBool True)) <|>
174 (string "False" >> return (LBool False))
176 parseLInt :: Parser Literal
181 parseLambda :: Parser Term
183 char '\\' <|> char 'λ' <|> char 'L'
184 vars <- sepBy1 parseVar (char ' ')
187 let (NTTerm l) = createLambda vars t
190 parseApp :: Parser Term
192 aps <- sepBy1 parseTypedTermNoApp (char ' ')
195 createLambda :: [Term] -> TypedTerm -> TypedTerm
196 createLambda (Var x : vs) t = NTTerm . Lam x $ createLambda vs t
197 createLambda [] t = t
198 createLambda _ _ = error "createLambda failed"
200 createApp :: [TypedTerm] -> Parser Term
201 createApp [t,ts] = return $ App t ts
202 createApp (t:ts:tss) = createApp (NTTerm (App t ts) : tss)
203 createApp _ = fail "not App"
207 -- TODO prop> t == tRead (show (t :: Term))