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.
19 import Data.Char (isAsciiLower, isAsciiUpper)
20 import Data.Text as T hiding (map)
21 import Data.Attoparsec.Text
22 import Control.Applicative
27 -- >>> import Test.QuickCheck
28 -- >>> import Test.HM.Term
31 -- >>> print $ Lam "x" (Var "x")
36 braced :: String -> String
37 braced t = "(" ++ t ++ ")"
39 instance Show Term where
41 show (Lam x (NTTerm (Lam y t))) = show (Lam (x ++ " " ++ y) t)
42 show (Lam x t) = braced $ "λ" ++ x ++ "." ++ show t
43 show (App a (NTTerm (App b c))) = show a ++ " " ++ braced ( show (App b c))
44 show (App t r) = show t ++ " " ++ show r
45 show (Let x e1 e2) = braced $ "LET " ++ x ++ " = " ++ show e1 ++ " IN " ++ show e2
47 instance Show TypedTerm where
48 show (NTTerm t) = show t
49 show (TTerm t tp) = braced $ show t ++ " :: " ++ show tp
51 instance Show Type where
52 show (Primitive t) = t
54 show (TypeFunction a b) = braced $ show a ++ " -> " ++ show b
56 instance Show TypeScheme where
57 show (TScheme t) = show t
58 show (TSForAll x t) = braced $ "∀" ++ x ++ ": " ++ show t
60 tRead :: String -> TypedTerm
61 tRead s = case parseOnly (parseTypedTerm <* endOfInput) (T.pack s) of
65 parseTerm :: Parser Term
66 parseTerm = parseLet <|>
71 parseTermNoApp :: Parser Term
72 parseTermNoApp = parseLet <|>
76 parseTypeAndTerm :: Parser Term -> Parser TypedTerm
77 parseTypeAndTerm p = do
81 return $! TTerm term tp
84 parseTypedTermNoApp :: Parser TypedTerm
85 parseTypedTermNoApp = parseBraces parseTypedTerm <|>
86 parseTypeAndTerm parseTermNoApp <|>
87 (NTTerm <$> parseTermNoApp)
89 parseTypedTerm :: Parser TypedTerm
90 parseTypedTerm = parseBraces parseTypedTerm <|>
91 parseTypeAndTerm parseTerm <|>
92 (NTTerm <$> parseTerm)
94 parseType :: Parser Type
95 parseType = parseBraces parseType <|>
100 parsePrimitive :: Parser Type
102 x <- many1 $ satisfy isAsciiUpper
103 return $! Primitive x
105 parseTypeVar :: Parser Type
107 x <- many1 $ satisfy isAsciiLower
110 parseTypeFunction :: Parser Type
111 parseTypeFunction = do
112 a <- parseBraces parseType <|> parsePrimitive <|> parseTypeVar
115 return $! TypeFunction a b
117 parseTypeScheme :: Parser TypeScheme
118 parseTypeScheme = parseBraces parseTypeScheme <|>
120 (TScheme <$> parseType)
122 parseForAll :: Parser TypeScheme
125 (TypeVar x) <- parseTypeVar
128 return $! TSForAll x t
130 parseBraces :: Parser a -> Parser a
137 parseLet :: Parser Term
145 return $! Let x e1 e2
147 parseVar :: Parser Term
149 x <- many1 $ satisfy isAsciiLower
152 parseLambda :: Parser Term
154 char '\\' <|> char 'λ' <|> char 'L'
155 vars <- sepBy1 parseVar (char ' ')
158 let (NTTerm l) = createLambda vars t
161 parseApp :: Parser Term
163 aps <- sepBy1 parseTypedTermNoApp (char ' ')
166 createLambda :: [Term] -> TypedTerm -> TypedTerm
167 createLambda (Var x : vs) t = NTTerm . Lam x $ createLambda vs t
168 createLambda [] t = t
169 createLambda _ _ = error "createLambda failed"
171 createApp :: [TypedTerm] -> Parser Term
172 createApp [t,ts] = return $ App t ts
173 createApp (t:ts:tss) = createApp (NTTerm (App t ts) : tss)
174 createApp _ = fail "not App"
178 -- TODO prop> t == tRead (show (t :: Term))