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 (Var x) tp) = x ++ " :: " ++ show tp
50 show (TTerm t tp) = braced (show t) ++ " :: " ++ show tp
52 instance Show Type where
53 show (Primitive t) = t
55 show (TypeFunction a b) = braced $ show a ++ " -> " ++ show b
57 instance Show TypeScheme where
58 show (TScheme t) = show t
59 show (TSForAll x t) = braced $ "∀" ++ x ++ ": " ++ show t
61 tRead :: String -> TypedTerm
62 tRead s = case parseOnly (parseTypedTerm <* endOfInput) (T.pack s) of
66 parseTerm :: Parser Term
67 parseTerm = parseLet <|>
69 parseBraces parseTerm <|>
73 parseTermNoApp :: Parser Term
74 parseTermNoApp = parseBraces parseTerm <|>
79 parseTypeAndTerm :: Parser Term -> Parser TypedTerm
80 parseTypeAndTerm p = do
84 return $! TTerm term tp
87 parseTypedTermNoApp :: Parser TypedTerm
88 parseTypedTermNoApp = parseTypeAndTerm parseTermNoApp <|>
89 parseBraces parseTypedTerm <|>
90 (NTTerm <$> parseTermNoApp)
92 parseTypedTerm :: Parser TypedTerm
93 parseTypedTerm = parseTypeAndTerm parseTerm <|>
94 parseBraces parseTypedTerm <|>
95 (NTTerm <$> parseTerm)
97 parseType :: Parser Type
98 parseType = parseBraces parseType <|>
103 parsePrimitive :: Parser Type
105 x <- many1 $ satisfy isAsciiUpper
106 return $! Primitive x
108 parseTypeVar :: Parser Type
110 x <- many1 $ satisfy isAsciiLower
113 parseTypeFunction :: Parser Type
114 parseTypeFunction = do
115 a <- parseBraces parseType <|> parsePrimitive <|> parseTypeVar
118 return $! TypeFunction a b
120 parseTypeScheme :: Parser TypeScheme
121 parseTypeScheme = parseBraces parseTypeScheme <|>
123 (TScheme <$> parseType)
125 parseForAll :: Parser TypeScheme
128 (TypeVar x) <- parseTypeVar
131 return $! TSForAll x t
133 parseBraces :: Parser a -> Parser a
140 parseLet :: Parser Term
148 return $! Let x e1 e2
150 parseVar :: Parser Term
152 x <- many1 $ satisfy isAsciiLower
155 parseLambda :: Parser Term
157 char '\\' <|> char 'λ' <|> char 'L'
158 vars <- sepBy1 parseVar (char ' ')
161 let (NTTerm l) = createLambda vars t
164 parseApp :: Parser Term
166 aps <- sepBy1 parseTypedTermNoApp (char ' ')
169 createLambda :: [Term] -> TypedTerm -> TypedTerm
170 createLambda (Var x : vs) t = NTTerm . Lam x $ createLambda vs t
171 createLambda [] t = t
172 createLambda _ _ = error "createLambda failed"
174 createApp :: [TypedTerm] -> Parser Term
175 createApp [t,ts] = return $ App t ts
176 createApp (t:ts:tss) = createApp (NTTerm (App t ts) : tss)
177 createApp _ = fail "not App"
181 -- TODO prop> t == tRead (show (t :: Term))