2024-10-05 13:31:09 -07:00
|
|
|
module Expr where
|
|
|
|
|
|
|
|
|
|
data Expr where
|
2024-11-22 19:44:31 -08:00
|
|
|
Var :: Text -> Integer -> Expr
|
2024-11-17 01:57:53 -08:00
|
|
|
Free :: Text -> Expr
|
2024-11-28 13:39:23 -08:00
|
|
|
Level :: Integer -> Expr
|
2024-10-06 14:02:35 -07:00
|
|
|
App :: Expr -> Expr -> Expr
|
2024-11-14 22:02:04 -08:00
|
|
|
Abs :: Text -> Expr -> Expr -> Expr
|
|
|
|
|
Pi :: Text -> Expr -> Expr -> Expr
|
2024-11-30 22:36:27 -08:00
|
|
|
Let :: Text -> Maybe Expr -> Expr -> Expr -> Expr
|
2024-11-17 01:57:53 -08:00
|
|
|
deriving (Show, Ord)
|
2024-11-11 23:38:10 -08:00
|
|
|
|
|
|
|
|
instance Eq Expr where
|
2024-11-22 19:44:31 -08:00
|
|
|
(Var _ n) == (Var _ m) = n == m
|
2024-11-20 07:37:49 -08:00
|
|
|
(Free s) == (Free t) = s == t
|
2024-11-28 13:39:23 -08:00
|
|
|
(Level i) == (Level j) = i == j
|
2024-11-11 23:38:10 -08:00
|
|
|
(App e1 e2) == (App f1 f2) = e1 == f1 && e2 == f2
|
|
|
|
|
(Abs _ t1 b1) == (Abs _ t2 b2) = t1 == t2 && b1 == b2
|
|
|
|
|
(Pi _ t1 b1) == (Pi _ t2 b2) = t1 == t2 && b1 == b2
|
2024-11-30 22:36:27 -08:00
|
|
|
(Let _ _ v1 b1) == (Let _ _ v2 b2) = v1 == v2 && b1 == b2
|
2024-11-11 23:38:10 -08:00
|
|
|
_ == _ = False
|
2024-10-06 14:02:35 -07:00
|
|
|
|
2024-11-11 13:43:28 -08:00
|
|
|
occursFree :: Integer -> Expr -> Bool
|
2024-11-22 19:44:31 -08:00
|
|
|
occursFree n (Var _ k) = n == k
|
2024-11-17 01:57:53 -08:00
|
|
|
occursFree _ (Free _) = False
|
2024-11-28 13:39:23 -08:00
|
|
|
occursFree _ (Level _) = False
|
2024-11-11 13:52:50 -08:00
|
|
|
occursFree n (App a b) = on (||) (occursFree n) a b
|
2024-11-11 14:10:27 -08:00
|
|
|
occursFree n (Abs _ a b) = occursFree n a || occursFree (n + 1) b
|
|
|
|
|
occursFree n (Pi _ a b) = occursFree n a || occursFree (n + 1) b
|
2024-11-30 22:36:27 -08:00
|
|
|
occursFree n (Let _ _ v b) = occursFree n v || occursFree (n + 1) b
|
2024-11-11 13:43:28 -08:00
|
|
|
|
2024-11-17 01:57:53 -08:00
|
|
|
shiftIndices :: Integer -> Integer -> Expr -> Expr
|
2024-11-22 19:44:31 -08:00
|
|
|
shiftIndices d c (Var x k)
|
|
|
|
|
| k >= c = Var x (k + d)
|
|
|
|
|
| otherwise = Var x k
|
2024-11-17 01:57:53 -08:00
|
|
|
shiftIndices _ _ (Free s) = Free s
|
2024-11-28 13:39:23 -08:00
|
|
|
shiftIndices _ _ (Level i) = Level i
|
2024-11-17 01:57:53 -08:00
|
|
|
shiftIndices d c (App m n) = App (shiftIndices d c m) (shiftIndices d c n)
|
|
|
|
|
shiftIndices d c (Abs x m n) = Abs x (shiftIndices d c m) (shiftIndices d (c + 1) n)
|
|
|
|
|
shiftIndices d c (Pi x m n) = Pi x (shiftIndices d c m) (shiftIndices d (c + 1) n)
|
2024-11-30 22:36:27 -08:00
|
|
|
shiftIndices d c (Let x t v b) = Let x t (shiftIndices d c v) (shiftIndices d (c + 1) b)
|
2024-11-17 01:57:53 -08:00
|
|
|
|
|
|
|
|
incIndices :: Expr -> Expr
|
|
|
|
|
incIndices = shiftIndices 1 0
|
|
|
|
|
|
2024-10-06 14:02:35 -07:00
|
|
|
{- --------------------- PRETTY PRINTING ----------------------------- -}
|
|
|
|
|
|
2024-11-14 22:02:04 -08:00
|
|
|
parenthesize :: Text -> Text
|
2024-11-22 19:44:31 -08:00
|
|
|
parenthesize s = "(" <> s <> ")"
|
2024-11-11 14:34:55 -08:00
|
|
|
|
2024-11-23 10:35:58 -08:00
|
|
|
type Param = (Text, Expr)
|
|
|
|
|
type ParamGroup = ([Text], Expr)
|
|
|
|
|
type Binding = (Text, [ParamGroup], Expr)
|
|
|
|
|
|
|
|
|
|
collectLambdas :: Expr -> ([Param], Expr)
|
2024-11-11 16:38:46 -08:00
|
|
|
collectLambdas (Abs x ty body) = ((x, ty) : params, final)
|
|
|
|
|
where
|
|
|
|
|
(params, final) = collectLambdas body
|
|
|
|
|
collectLambdas e = ([], e)
|
|
|
|
|
|
2024-11-23 10:35:58 -08:00
|
|
|
collectLets :: Expr -> ([Binding], Expr)
|
2024-11-30 22:36:27 -08:00
|
|
|
collectLets (Let x _ val body) = ((x, params', val') : bindings, final)
|
2024-11-23 09:16:32 -08:00
|
|
|
where
|
2024-11-23 10:35:58 -08:00
|
|
|
(bindings, final) = collectLets body
|
|
|
|
|
(params, val') = collectLambdas val
|
|
|
|
|
params' = groupParams params
|
2024-11-23 09:16:32 -08:00
|
|
|
collectLets e = ([], e)
|
2024-11-17 18:33:14 -08:00
|
|
|
|
2024-11-23 10:35:58 -08:00
|
|
|
collectPis :: Expr -> ([Param], Expr)
|
2024-11-11 16:38:46 -08:00
|
|
|
collectPis p@(Pi "" _ _) = ([], p)
|
|
|
|
|
collectPis (Pi x ty body) = ((x, ty) : params, final)
|
|
|
|
|
where
|
|
|
|
|
(params, final) = collectPis body
|
|
|
|
|
collectPis e = ([], e)
|
|
|
|
|
|
2024-11-23 09:16:32 -08:00
|
|
|
cleanNames :: Expr -> Expr
|
|
|
|
|
cleanNames (App m n) = App (cleanNames m) (cleanNames n)
|
|
|
|
|
cleanNames (Abs x ty body) = Abs x (cleanNames ty) (cleanNames body)
|
|
|
|
|
cleanNames (Pi x ty body)
|
|
|
|
|
| occursFree 0 body = Pi x (cleanNames ty) (cleanNames body)
|
|
|
|
|
| otherwise = Pi "" ty (cleanNames body)
|
|
|
|
|
cleanNames e = e
|
|
|
|
|
|
2024-11-23 10:35:58 -08:00
|
|
|
groupParams :: [Param] -> [ParamGroup]
|
2024-11-11 16:38:46 -08:00
|
|
|
groupParams = foldr addParam []
|
|
|
|
|
where
|
2024-11-14 22:02:04 -08:00
|
|
|
addParam :: (Text, Expr) -> [([Text], Expr)] -> [([Text], Expr)]
|
2024-11-11 16:38:46 -08:00
|
|
|
addParam (x, t) [] = [([x], t)]
|
|
|
|
|
addParam (x, t) l@((xs, s) : rest)
|
2024-11-11 23:38:10 -08:00
|
|
|
| incIndices t == s = (x : xs, t) : rest
|
2024-11-11 16:38:46 -08:00
|
|
|
| otherwise = ([x], t) : l
|
|
|
|
|
|
2024-11-23 10:35:58 -08:00
|
|
|
showParamGroup :: ParamGroup -> Text
|
2024-11-22 19:44:31 -08:00
|
|
|
showParamGroup (ids, ty) = parenthesize $ unwords ids <> " : " <> pretty ty
|
2024-11-11 16:38:46 -08:00
|
|
|
|
2024-11-23 10:35:58 -08:00
|
|
|
showBinding :: Binding -> Text
|
|
|
|
|
showBinding (ident, params, val) =
|
|
|
|
|
parenthesize $
|
|
|
|
|
ident
|
|
|
|
|
<> " "
|
|
|
|
|
<> unwords (map showParamGroup params)
|
|
|
|
|
<> " := "
|
|
|
|
|
<> pretty val
|
2024-11-23 09:16:32 -08:00
|
|
|
|
2024-11-14 22:02:04 -08:00
|
|
|
helper :: Integer -> Expr -> Text
|
2024-11-22 19:44:31 -08:00
|
|
|
helper _ (Var s _) = s
|
2024-11-17 01:57:53 -08:00
|
|
|
helper _ (Free s) = s
|
2024-11-28 13:39:23 -08:00
|
|
|
helper _ (Level i)
|
|
|
|
|
| i == 0 = "*"
|
|
|
|
|
| otherwise = "*" <> show i
|
2024-11-11 16:38:46 -08:00
|
|
|
helper k (App e1 e2) = if k > 3 then parenthesize res else res
|
2024-11-11 14:34:55 -08:00
|
|
|
where
|
2024-11-14 22:02:04 -08:00
|
|
|
res = helper 3 e1 <> " " <> helper 4 e2
|
2024-11-11 16:38:46 -08:00
|
|
|
helper k (Pi "" t1 t2) = if k > 2 then parenthesize res else res
|
2024-11-11 23:38:10 -08:00
|
|
|
where
|
2024-11-14 22:02:04 -08:00
|
|
|
res = helper 3 t1 <> " -> " <> helper 2 t2
|
2024-11-11 16:38:46 -08:00
|
|
|
helper k e@(Pi{}) = if k > 2 then parenthesize res else res
|
2024-11-11 14:34:55 -08:00
|
|
|
where
|
2024-11-11 16:38:46 -08:00
|
|
|
(params, body) = collectPis e
|
|
|
|
|
grouped = showParamGroup <$> groupParams params
|
2024-11-22 19:44:31 -08:00
|
|
|
res = "∏ " <> unwords grouped <> " . " <> pretty body
|
2024-11-11 16:38:46 -08:00
|
|
|
helper k e@(Abs{}) = if k >= 1 then parenthesize res else res
|
2024-11-11 14:34:55 -08:00
|
|
|
where
|
2024-11-11 16:38:46 -08:00
|
|
|
(params, body) = collectLambdas e
|
|
|
|
|
grouped = showParamGroup <$> groupParams params
|
2024-11-22 19:44:31 -08:00
|
|
|
res = "λ " <> unwords grouped <> " . " <> pretty body
|
2024-11-23 09:16:32 -08:00
|
|
|
helper _ e@(Let{}) = res
|
|
|
|
|
where
|
|
|
|
|
(binds, body) = collectLets e
|
|
|
|
|
res = "let " <> unwords (map showBinding binds) <> " in " <> pretty body <> " end"
|
2024-11-11 14:34:55 -08:00
|
|
|
|
2024-11-14 22:02:04 -08:00
|
|
|
pretty :: Expr -> Text
|
2024-11-17 18:33:14 -08:00
|
|
|
pretty = helper 0 . cleanNames
|
2024-10-06 14:02:35 -07:00
|
|
|
|
2024-11-14 22:02:04 -08:00
|
|
|
prettyS :: Expr -> String
|
2024-11-22 19:44:31 -08:00
|
|
|
prettyS = toString . pretty
|