shithub: MicroHs

Download patch

ref: 4c2cb9e52fa8690e2864e2b5da24c1295d53a32e
parent: 956624b4ea52a226fb82919b3ab4687628fc59b5
author: Lennart Augustsson <lennart@augustsson.net>
date: Wed Dec 27 10:58:44 EST 2023

Implement deriving Eq

--- a/src/MicroHs/Deriving.hs
+++ b/src/MicroHs/Deriving.hs
@@ -73,7 +73,7 @@
 derivers :: [(String, Deriver)]
 derivers =
   [("Data.Typeable.Typeable", derTypeable)
-  ,("Data.Eq.Eq",             derNotYet)
+  ,("Data.Eq.Eq",             derEq)
   ,("Data.Ord.Ord",           derNotYet)
   ,("Text.Show.Show",         derNotYet)
   ]
@@ -90,6 +90,8 @@
   traceM ("Warning: cannot derive " ++ show d ++ " yet, " ++ showSLoc (getSLoc d))
   return []
 
+--------------------------------------------
+
 derTypeable :: Deriver
 derTypeable (i, _) _ etyp = do
   mn <- gets moduleName
@@ -103,4 +105,47 @@
     nam = ELit loc $ LStr $ unIdent i
     eqns = eEqns [dummy] $ eApp2 (EVar imkTyConApp) (eApp2 (EVar imkTyCon) mdl nam) (EVar (mkIdent "[]"))
     inst = Instance hdr [BFcn itypeRep eqns]
+  return [inst]
+
+--------------------------------------------
+
+getConstrTyVars :: Constr -> [Ident]
+getConstrTyVars (Constr evs ctx _ flds) =
+  let vs = freeTyVars $ ctx ++ either (map snd) (map (snd . snd)) flds
+  in  vs \\ map idKindIdent evs
+
+mkHdr :: LHS -> [Constr] -> EConstraint -> T EConstraint
+mkHdr (t, iks) cs cls = do
+  mn <- gets moduleName
+  let used = foldr (union . getConstrTyVars) [] cs  -- Used type variables
+      iks' = filter ((`elem` used) . idKindIdent) iks
+      vs = map tVarK iks'
+      ty = tApps (qualIdent mn t) $ map tVarK iks
+  pure $ eForall iks $ addConstraints (map (tApp cls) vs) $ tApp cls ty
+
+mkPat :: Constr -> String -> (EPat, [Expr])
+mkPat (Constr _ _ c flds) s =
+  let n = either length length flds
+      loc = getSLoc c
+      vs = map (EVar . mkIdentSLoc loc . (s ++) . show) [1..n]
+  in  (tApps c vs, vs)
+
+--------------------------------------------
+
+derEq :: Deriver
+derEq lhs cs eeq = do
+  hdr <- mkHdr lhs cs eeq
+  let loc = getSLoc eeq
+      mkEqn c =
+        let (xp, xs) = mkPat c "x"
+            (yp, ys) = mkPat c "y"
+        in  eEqn [xp, yp] $ if null xs then eTrue else foldr1 eAnd $ zipWith eEq xs ys
+      eqns = map mkEqn cs ++ [eEqn [dummy, dummy] eFalse]
+      iEq = mkIdentSLoc loc "=="
+      eEq = EApp . EApp (EVar iEq)
+      eAnd = EApp . EApp (EVar $ mkIdentSLoc loc "&&")
+      eTrue = EVar $ mkIdentSLoc loc "True"
+      eFalse = EVar $ mkIdentSLoc loc "False"
+      inst = Instance hdr [BFcn iEq eqns]
+--  traceM $ showEDefs [inst]
   return [inst]
--- a/src/MicroHs/TCMonad.hs
+++ b/src/MicroHs/TCMonad.hs
@@ -321,3 +321,60 @@
 getAppCon (EApp f _) = getAppCon f
 getAppCon _ = error "getAppCon"
 
+-----------------------------------------------
+
+type TyVar = Ident
+
+freeTyVars :: [EType] -> [TyVar]
+-- Get the free TyVars from a type; no duplicates in result
+freeTyVars = foldr (go []) []
+  where
+    go :: [TyVar] -- Ignore occurrences of bound type variables
+       -> EType   -- Type to look at
+       -> [TyVar] -- Accumulates result
+       -> [TyVar]
+    go bound (EVar tv) acc
+      | elem tv bound = acc
+      | elem tv acc = acc
+      | isConIdent tv = acc
+      | otherwise = tv : acc
+    go bound (EForall tvs ty) acc = go (map idKindIdent tvs ++ bound) ty acc
+    go bound (EApp fun arg) acc = go bound fun (go bound arg acc)
+    go _bound (EUVar _) acc = acc
+    go _ _ _ = undefined
+
+addConstraints :: [EConstraint] -> EType -> EType
+addConstraints []  t = t
+addConstraints cs  t = tupleConstraints cs `tImplies` t
+
+tupleConstraints :: [EConstraint] -> EConstraint
+tupleConstraints []  = error "tupleConstraints"
+tupleConstraints [c] = c
+tupleConstraints cs  = tApps (tupleConstr noSLoc (length cs)) cs
+
+-----------------------------------------------
+
+builtinLoc :: SLoc
+builtinLoc = SLoc "builtin" 0 0
+
+tConI :: SLoc -> String -> EType
+tConI loc = tCon . mkIdentSLoc loc
+
+tCon :: Ident -> EType
+tCon = EVar
+
+tVarK :: IdKind -> EType
+tVarK (IdKind i _) = EVar i
+
+tApp :: EType -> EType -> EType
+tApp = EApp
+
+tApps :: Ident -> [EType] -> EType
+tApps i ts = foldl tApp (tCon i) ts
+
+tArrow :: EType -> EType -> EType
+tArrow a r = tApp (tApp (tConI builtinLoc "Primitives.->") a) r
+
+tImplies :: EType -> EType -> EType
+tImplies a r = tApp (tApp (tConI builtinLoc "Primitives.=>") a) r
+
--- a/src/MicroHs/TypeCheck.hs
+++ b/src/MicroHs/TypeCheck.hs
@@ -123,7 +123,6 @@
 type Sigma = EType
 --type Tau   = EType
 type Rho   = EType
-type TyVar = Ident
 
 typeCheck :: forall a . [(ImportSpec, TModule a)] -> EModule -> TModule [EDef]
 typeCheck aimps (EModule mn exps defs) =
@@ -474,9 +473,6 @@
 kTypeTypeConstraintS :: EType
 kTypeTypeConstraintS = kArrow kType (kArrow kType kConstraint)
 
-builtinLoc :: SLoc
-builtinLoc = SLoc "builtin" 0 0
-
 mkIdentB :: String -> Ident
 mkIdentB = mkIdentSLoc builtinLoc
 
@@ -563,24 +559,6 @@
       in  (c, [Entry (ECon $ ConData [(c, n)] c []) $ EForall vks $ foldr tArrow r ts ])
   in  map tuple (enumFromTo 2 10)
 
-tCon :: Ident -> EType
-tCon = EVar
-
-tVarK :: IdKind -> EType
-tVarK (IdKind i _) = EVar i
-
-tApp :: EType -> EType -> EType
-tApp = EApp
-
-tApps :: Ident -> [EType] -> EType
-tApps i ts = foldl tApp (tCon i) ts
-
-tArrow :: EType -> EType -> EType
-tArrow a r = tApp (tApp (tConI builtinLoc "Primitives.->") a) r
-
-tImplies :: EType -> EType -> EType
-tImplies a r = tApp (tApp (tConI builtinLoc "Primitives.=>") a) r
-
 kArrow :: EKind -> EKind -> EKind
 kArrow = tArrow
 
@@ -1137,15 +1115,6 @@
   usup []
 -}
 
-addConstraints :: [EConstraint] -> EType -> EType
-addConstraints []  t = t
-addConstraints cs  t = tupleConstraints cs `tImplies` t
-
-tupleConstraints :: [EConstraint] -> EConstraint
-tupleConstraints []  = error "tupleConstraints"
-tupleConstraints [c] = c
-tupleConstraints cs  = tApps (tupleConstr noSLoc (length cs)) cs
-
 splitInst :: EConstraint -> ([IdKind], [EConstraint], EConstraint)
 splitInst (EForall iks t) =
   case splitInst t of
@@ -2008,9 +1977,6 @@
     ELit _ (LInteger _) -> at
     _ -> impossible
 
-tConI :: SLoc -> String -> EType
-tConI loc = tCon . mkIdentSLoc loc
-
 tListI :: SLoc -> Ident
 tListI loc = mkIdentSLoc loc $ listPrefix ++ "[]"
 
@@ -2097,24 +2063,6 @@
 newSkolemTyVar tv = do
   uniq <- newUniq
   return (mkIdentSLoc (getSLoc tv) (unIdent tv ++ "#" ++ show uniq))
-
-freeTyVars :: [EType] -> [TyVar]
--- Get the free TyVars from a type; no duplicates in result
-freeTyVars = foldr (go []) []
-  where
-    go :: [TyVar] -- Ignore occurrences of bound type variables
-       -> EType   -- Type to look at
-       -> [TyVar] -- Accumulates result
-       -> [TyVar]
-    go bound (EVar tv) acc
-      | elem tv bound = acc
-      | elem tv acc = acc
-      | isConIdent tv = acc
-      | otherwise = tv : acc
-    go bound (EForall tvs ty) acc = go (map idKindIdent tvs ++ bound) ty acc
-    go bound (EApp fun arg) acc = go bound fun (go bound arg acc)
-    go _bound (EUVar _) acc = acc
-    go _ _ _ = undefined
 
 metaTvs :: [EType] -> [TRef]
 -- Get the MetaTvs from a type; no duplicates in result
--- /dev/null
+++ b/tests/Deriving.hs
@@ -1,0 +1,14 @@
+module Deriving(main) where
+import Prelude
+
+data T a b c = A a | B b | C a Int | D
+  deriving Eq
+
+main :: IO ()
+main = do
+  print $ A 'a' == (A 'a' :: T Char () ())
+  print $ A 'a' == (A 'b' :: T Char () ())
+  print $ A 'a' == B False
+  print $ C 'a' 1 == (C 'a' 1 :: T Char () ())
+  print $ C 'a' 1 == (C 'a' 2 :: T Char () ())
+  print $ D == (D :: T () () ())
--- /dev/null
+++ b/tests/Deriving.ref
@@ -1,0 +1,6 @@
+True
+False
+False
+True
+False
+True
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -55,6 +55,7 @@
 	$(TMHS) HigherKind && $(EVAL) > HigherKind.out && diff HigherKind.ref HigherKind.out
 	$(TMHS) PolyKind   && $(EVAL) > PolyKind.out   && diff PolyKind.ref PolyKind.out
 	$(TMHS) Record     && $(EVAL) > Record.out     && diff Record.ref Record.out
+	$(TMHS) Deriving   && $(EVAL) > Deriving.out   && diff Deriving.ref Deriving.out
 
 errtest:
 	sh errtester.sh < errmsg.test
--