1 Commits

Author SHA1 Message Date
crumbtoo
f01164bf01 diagrams 2024-02-15 22:06:41 -07:00
7 changed files with 373 additions and 282 deletions

View File

@@ -74,6 +74,11 @@ options = RLPCOptions
<> metavar "rlp|core" <> metavar "rlp|core"
<> help "the language to be compiled -- see README" <> help "the language to be compiled -- see README"
) )
<*> flag False True
( long "render"
<> short 'r'
<> help "render a diagram of each GM state"
)
<*> some (argument str $ metavar "FILES...") <*> some (argument str $ metavar "FILES...")
where where
infixr 9 # infixr 9 #

View File

@@ -22,6 +22,9 @@ library
exposed-modules: Core exposed-modules: Core
, TI , TI
, GM , GM
, GM.Visual
, GM.Types
, GM.Print
, Compiler.RLPC , Compiler.RLPC
, Compiler.RlpcError , Compiler.RlpcError
, Compiler.JustRun , Compiler.JustRun
@@ -73,6 +76,9 @@ library
, effectful-core ^>=2.3.0.0 , effectful-core ^>=2.3.0.0
, deriving-compat ^>=0.6.0 , deriving-compat ^>=0.6.0
, these >=0.2 && <2.0 , these >=0.2 && <2.0
, diagrams
, diagrams-lib
, diagrams-cairo
hs-source-dirs: src hs-source-dirs: src
default-language: GHC2021 default-language: GHC2021

View File

@@ -120,6 +120,7 @@ data RLPCOptions = RLPCOptions
, _rlpcEvaluator :: Evaluator , _rlpcEvaluator :: Evaluator
, _rlpcHeapTrigger :: Int , _rlpcHeapTrigger :: Int
, _rlpcLanguage :: Maybe Language , _rlpcLanguage :: Maybe Language
, _rlpcRender :: Bool
, _rlpcInputFiles :: [FilePath] , _rlpcInputFiles :: [FilePath]
} }
deriving Show deriving Show
@@ -141,6 +142,7 @@ instance Default RLPCOptions where
, _rlpcHeapTrigger = 200 , _rlpcHeapTrigger = 200
, _rlpcInputFiles = [] , _rlpcInputFiles = []
, _rlpcLanguage = Nothing , _rlpcLanguage = Nothing
, _rlpcRender = False
} }
-- debug flags are passed with -dFLAG -- debug flags are passed with -dFLAG

319
src/GM.hs
View File

@@ -11,6 +11,11 @@ module GM
, evalProgR , evalProgR
, GmState(..) , GmState(..)
, gmCode, gmStack, gmDump, gmHeap, gmEnv, gmStats , gmCode, gmStack, gmDump, gmHeap, gmEnv, gmStats
, stsReductions
, stsPrimReductions
, stsAllocations
, stsDereferences
, stsGCCycles
, Node(..) , Node(..)
, showState , showState
, gmEvalProg , gmEvalProg
@@ -29,10 +34,9 @@ import Data.Tuple (swap)
import Control.Lens import Control.Lens
import Data.Text.Lens (IsText, packed, unpacked) import Data.Text.Lens (IsText, packed, unpacked)
import Text.Printf import Text.Printf
import Text.PrettyPrint hiding ((<>))
import Text.PrettyPrint.HughesPJ (maybeParens)
import Data.Foldable (traverse_) import Data.Foldable (traverse_)
import System.IO (Handle, hPutStrLn) import System.IO (Handle, hPutStrLn)
import Text.PrettyPrint (render)
-- TODO: an actual output system -- TODO: an actual output system
-- TODO: an actual output system -- TODO: an actual output system
-- TODO: an actual output system -- TODO: an actual output system
@@ -41,9 +45,12 @@ import System.IO.Unsafe (unsafePerformIO)
import Data.String (IsString) import Data.String (IsString)
import Data.Heap import Data.Heap
import Debug.Trace import Debug.Trace
import Compiler.RLPC import Compiler.RLPC
import Core2Core import Core2Core
import Core import Core
import GM.Types
import GM.Print
---------------------------------------------------------------------------------- ----------------------------------------------------------------------------------
tag_Unit_unit :: Int tag_Unit_unit :: Int
@@ -55,105 +62,19 @@ tag_Bool_True = 1
tag_Bool_False :: Int tag_Bool_False :: Int
tag_Bool_False = 0 tag_Bool_False = 0
{-}
hdbgProg = undefined
evalProg = undefined
data Node = NNum Int
| NAp Addr Addr
| NInd Addr
| NUninitialised
| NConstr Tag [Addr] -- NConstr Tag Components
| NMarked Node
deriving (Show, Eq)
--}
data GmState = GmState
{ _gmCode :: Code
, _gmStack :: Stack
, _gmDump :: Dump
, _gmHeap :: GmHeap
, _gmEnv :: Env
, _gmStats :: Stats
}
deriving Show
type Code = [Instr]
type Stack = [Addr]
type Dump = [(Code, Stack)]
type Env = [(Key, Addr)]
type GmHeap = Heap Node
data Key = NameKey Name
| ConstrKey Tag Int
deriving (Show, Eq)
-- >> [ref/Instr]
data Instr = Unwind
| PushGlobal Name
| PushConstr Tag Int
| PushInt Int
| Push Int
| MkAp
| Slide Int
| Update Int
| Pop Int
| Alloc Int
| Eval
-- arith
| Neg | Add | Sub | Mul | Div
-- comparison
| Equals | Lesser | GreaterEq
| Pack Tag Int -- Pack Tag Arity
| CaseJump [(Tag, Code)]
| Split Int
| Print
| Halt
deriving (Show, Eq)
-- << [ref/Instr]
data Node = NNum Int
| NAp Addr Addr
-- NGlobal is the GM equivalent of NSupercomb. rather than storing a
-- template to be instantiated, NGlobal holds the global's arity and
-- the pre-compiled code :3
| NGlobal Int Code
| NInd Addr
| NUninitialised
| NConstr Tag [Addr] -- NConstr Tag Components
| NMarked Node
deriving (Show, Eq)
-- TODO: log executed instructions
data Stats = Stats
{ _stsReductions :: Int
, _stsPrimReductions :: Int
, _stsAllocations :: Int
, _stsDereferences :: Int
, _stsGCCycles :: Int
}
deriving Show
instance Default Stats where
def = Stats 0 0 0 0 0
-- TODO: _gmGlobals should not have a setter
makeLenses ''GmState
makeLenses ''Stats
pure []
---------------------------------------------------------------------------------- ----------------------------------------------------------------------------------
evalProg :: Program' -> Maybe (Node, Stats) evalProg :: Program' -> [GmState]
evalProg p = res <&> (,sts) evalProg = eval . compile
where
final = eval (compile p) & last -- evalProg :: Program' -> Maybe (Node, Stats)
h = final ^. gmHeap -- evalProg p = res <&> (,sts)
sts = final ^. gmStats -- where
resAddr = final ^. gmStack ^? _head -- final = eval (compile p) & last
res = resAddr >>= flip hLookup h -- h = final ^. gmHeap
-- sts = final ^. gmStats
-- resAddr = final ^. gmStack ^? _head
-- res = resAddr >>= flip hLookup h
hdbgProg :: Program' -> Handle -> IO GmState hdbgProg :: Program' -> Handle -> IO GmState
hdbgProg p hio = do hdbgProg p hio = do
@@ -815,185 +736,8 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil
argOffset :: Int -> Env -> Env argOffset :: Int -> Env -> Env
argOffset n = each . _2 %~ (+n) argOffset n = each . _2 %~ (+n)
showCon :: (IsText a) => Tag -> Int -> a
showCon t n = printf "Pack{%d %d}" t n ^. packed
---------------------------------------------------------------------------------- ----------------------------------------------------------------------------------
pprTabstop :: Int
pprTabstop = 4
qquotes :: Doc -> Doc
qquotes d = "`" <> d <> "'"
showStats :: Stats -> Doc
showStats sts = "==== Stats ============" $$ stats
where
stats = text $ printf
"Reductions : %5d\n\
\Prim Reductions : %5d\n\
\Allocations : %5d\n\
\GC Cycles : %5d"
(sts ^. stsReductions)
(sts ^. stsPrimReductions)
(sts ^. stsAllocations)
(sts ^. stsGCCycles)
showState :: GmState -> Doc
showState st = vcat
[ "==== GmState " <> int stnum <> " "
<> text (replicate (28 - 13 - 1 - digitalWidth stnum) '=')
, "-- Next instructions -------"
, info $ showCodeShort c
, "-- Stack -------------------"
, info $ showStack st
, "-- Heap --------------------"
, info $ showHeap st
, "-- Dump --------------------"
, info $ showDump st
]
where
stnum = st ^. (gmStats . stsReductions)
c = st ^. gmCode
-- indent data
info = nest pprTabstop
showCodeShort :: Code -> Doc
showCodeShort c = braces c'
where
c' | length c > 3 = list (showInstr <$> take 3 c) <> "; ..."
| otherwise = list (showInstr <$> c)
list = hcat . punctuate "; "
showStackShort :: Stack -> Doc
showStackShort s = brackets s'
where
-- no access to heap, otherwise we'd use showNodeAt
s' | length s > 3 = list (showEntry <$> take 3 s) <> ", ..."
| otherwise = list (showEntry <$> s)
list = hcat . punctuate ", "
showEntry = text . show
showStack :: GmState -> Doc
showStack st = vcat $ uncurry showEntry <$> si
where
h = st ^. gmHeap
s = st ^. gmStack
-- stack with labeled indices
si = [0..] `zip` s
w = maxWidth (addresses h)
showIndex n = padInt w n <> ": "
showEntry :: Int -> Addr -> Doc
showEntry n a = showIndex n <> showNodeAt st a
showDump :: GmState -> Doc
showDump st = vcat $ uncurry showEntry <$> di
where
d = st ^. gmDump
di = [0..] `zip` d
showIndex n = padInt w n <> ": "
w = maxWidth (fst <$> di)
showEntry :: Int -> (Code, Stack) -> Doc
showEntry n (c,s) = showIndex n <> nest pprTabstop entry
where
entry = ("Stack : " <> showCodeShort c)
$$ ("Code : " <> showStackShort s)
padInt :: Int -> Int -> Doc
padInt m n = text (replicate (m - digitalWidth n) ' ') <> int n
maxWidth :: [Int] -> Int
maxWidth ns = digitalWidth $ maximum ns
digitalWidth :: Int -> Int
digitalWidth = length . show
showHeap :: GmState -> Doc
showHeap st = vcat $ showEntry <$> addrs
where
showAddr n = padInt w n <> ": "
w = maxWidth addrs
h = st ^. gmHeap
addrs = addresses h
showEntry :: Addr -> Doc
showEntry a = showAddr a <> showNodeAt st a
showNodeAt :: GmState -> Addr -> Doc
showNodeAt = showNodeAtP 0
showNodeAtP :: Int -> GmState -> Addr -> Doc
showNodeAtP p st a = case hLookup a h of
Just (NNum n) -> int n <> "#"
Just (NGlobal _ _) -> textt name
where
g = st ^. gmEnv
name = case lookup a (swap <$> g) of
Just (NameKey n) -> n
Just (ConstrKey t n) -> showCon t n
_ -> errTxtInvalidAddress
-- TODO: left-associativity
Just (NAp f x) -> pprec $ showNodeAtP (p+1) st f
<+> showNodeAtP (p+1) st x
Just (NInd a') -> pprec $ "NInd -> " <> showNodeAtP (p+1) st a'
Just (NConstr t as) -> pprec $ "NConstr"
<+> int t
<+> brackets (list $ showNodeAtP 0 st <$> as)
where list = hcat . punctuate ", "
Just NUninitialised -> "<uninitialised>"
Nothing -> errTxtInvalidAddress
where
h = st ^. gmHeap
pprec = maybeParens (p > 0)
showSc :: GmState -> (Name, Addr) -> Doc
showSc st (k,a) = "Supercomb " <> qquotes (textt k) <> colon
$$ code
where
code = case hLookup a (st ^. gmHeap) of
Just (NGlobal _ c) -> showCode c
Just _ -> errTxtInvalidObject
Nothing -> errTxtInvalidAddress
errTxtInvalidObject, errTxtInvalidAddress :: (IsString a) => a
errTxtInvalidObject = "<invalid object>"
errTxtInvalidAddress = "<invalid address>"
showCode :: Code -> Doc
showCode c = "Code" <+> braces instrs
where instrs = vcat $ showInstr <$> c
showInstr :: Instr -> Doc
showInstr (CaseJump alts) = "CaseJump" $$ nest pprTabstop alternatives
where
showAlt (t,c) = "<" <> int t <> ">" <> showCodeShort c
alternatives = foldr (\a acc -> showAlt a $$ acc) mempty alts
showInstr i = text $ show i
textt :: (IsText a) => a -> Doc
textt t = t ^. unpacked & text
----------------------------------------------------------------------------------
lookupN :: Name -> Env -> Maybe Addr
lookupN k = lookup (NameKey k)
lookupC :: Tag -> Int -> Env -> Maybe Addr
lookupC t n = lookup (ConstrKey t n)
----------------------------------------------------------------------------------
gc :: GmState -> GmState
gc st = (sweepNodes . markNodes $ st)
& gmStats . stsGCCycles %~ succ
markNodes :: GmState -> GmState markNodes :: GmState -> GmState
markNodes st = st & gmHeap %~ thread (markFrom <$> roots) markNodes st = st & gmHeap %~ thread (markFrom <$> roots)
where where
@@ -1036,6 +780,18 @@ sweepNodes st = st & gmHeap %~ thread (f <$> addresses h)
thread :: [a -> a] -> (a -> a) thread :: [a -> a] -> (a -> a)
thread = appEndo . foldMap Endo thread = appEndo . foldMap Endo
gc :: GmState -> GmState
gc st = (sweepNodes . markNodes $ st)
& gmStats . stsGCCycles %~ succ
--------------------------------------------------------------------------------
lookupN :: Name -> Env -> Maybe Addr
lookupN k = lookup (NameKey k)
lookupC :: Tag -> Int -> Env -> Maybe Addr
lookupC t n = lookup (ConstrKey t n)
---------------------------------------------------------------------------------- ----------------------------------------------------------------------------------
gmEvalProg :: Program' -> GmState gmEvalProg :: Program' -> GmState
@@ -1047,12 +803,11 @@ finalStateOf f = f . gmEvalProg
resultOf :: Program' -> Maybe Node resultOf :: Program' -> Maybe Node
resultOf p = do resultOf p = do
a <- res a <- res
n <- hLookup a h hLookup a h
pure n where
where res = st ^? gmStack . _head
res = st ^? gmStack . _head st = gmEvalProg p
st = gmEvalProg p h = st ^. gmHeap
h = st ^. gmHeap
resultOfExpr :: Expr' -> Maybe Node resultOfExpr :: Expr' -> Maybe Node
resultOfExpr e = resultOf $ resultOfExpr e = resultOf $

186
src/GM/Print.hs Normal file
View File

@@ -0,0 +1,186 @@
module GM.Print
( showState
, showStats
, showNodeAt
)
where
--------------------------------------------------------------------------------
import Data.Monoid
import Data.String (IsString(..))
import Data.Text.Lens (IsText, packed, unpacked)
import Text.Printf
import Text.PrettyPrint hiding ((<>))
import Text.PrettyPrint.HughesPJ (maybeParens)
import Control.Lens
import Data.Heap
import Core.Syntax
import GM.Types
--------------------------------------------------------------------------------
pprTabstop :: Int
pprTabstop = 4
qquotes :: Doc -> Doc
qquotes d = "`" <> d <> "'"
showStats :: Stats -> Doc
showStats sts = "==== Stats ============" $$ stats
where
stats = text $ printf
"Reductions : %5d\n\
\Prim Reductions : %5d\n\
\Allocations : %5d\n\
\GC Cycles : %5d"
(sts ^. stsReductions)
(sts ^. stsPrimReductions)
(sts ^. stsAllocations)
(sts ^. stsGCCycles)
showState :: GmState -> Doc
showState st = vcat
[ "==== GmState " <> int stnum <> " "
<> text (replicate (28 - 13 - 1 - digitalWidth stnum) '=')
, "-- Next instructions -------"
, info $ showCodeShort c
, "-- Stack -------------------"
, info $ showStack st
, "-- Heap --------------------"
, info $ showHeap st
, "-- Dump --------------------"
, info $ showDump st
]
where
stnum = st ^. (gmStats . stsReductions)
c = st ^. gmCode
-- indent data
info = nest pprTabstop
showCodeShort :: Code -> Doc
showCodeShort c = braces c'
where
c' | length c > 3 = list (showInstr <$> take 3 c) <> "; ..."
| otherwise = list (showInstr <$> c)
list = hcat . punctuate "; "
showStackShort :: Stack -> Doc
showStackShort s = brackets s'
where
-- no access to heap, otherwise we'd use showNodeAt
s' | length s > 3 = list (showEntry <$> take 3 s) <> ", ..."
| otherwise = list (showEntry <$> s)
list = hcat . punctuate ", "
showEntry = text . show
showStack :: GmState -> Doc
showStack st = vcat $ uncurry showEntry <$> si
where
h = st ^. gmHeap
s = st ^. gmStack
-- stack with labeled indices
si = [0..] `zip` s
w = maxWidth (addresses h)
showIndex n = padInt w n <> ": "
showEntry :: Int -> Addr -> Doc
showEntry n a = showIndex n <> showNodeAt st a
showDump :: GmState -> Doc
showDump st = vcat $ uncurry showEntry <$> di
where
d = st ^. gmDump
di = [0..] `zip` d
showIndex n = padInt w n <> ": "
w = maxWidth (fst <$> di)
showEntry :: Int -> (Code, Stack) -> Doc
showEntry n (c,s) = showIndex n <> nest pprTabstop entry
where
entry = ("Stack : " <> showCodeShort c)
$$ ("Code : " <> showStackShort s)
padInt :: Int -> Int -> Doc
padInt m n = text (replicate (m - digitalWidth n) ' ') <> int n
maxWidth :: [Int] -> Int
maxWidth ns = digitalWidth $ maximum ns
digitalWidth :: Int -> Int
digitalWidth = length . show
showHeap :: GmState -> Doc
showHeap st = vcat $ showEntry <$> addrs
where
showAddr n = padInt w n <> ": "
w = maxWidth addrs
h = st ^. gmHeap
addrs = addresses h
showEntry :: Addr -> Doc
showEntry a = showAddr a <> showNodeAt st a
showNodeAt :: GmState -> Addr -> Doc
showNodeAt = showNodeAtP 0
showNodeAtP :: Int -> GmState -> Addr -> Doc
showNodeAtP p st a = case hLookup a h of
Just (NNum n) -> int n <> "#"
Just (NGlobal _ _) -> textt name
where
g = st ^. gmEnv
name = case lookup a (view swapped <$> g) of
Just (NameKey n) -> n
Just (ConstrKey t n) -> showCon t n
_ -> errTxtInvalidAddress
-- TODO: left-associativity
Just (NAp f x) -> pprec $ showNodeAtP (p+1) st f
<+> showNodeAtP (p+1) st x
Just (NInd a') -> pprec $ "NInd -> " <> showNodeAtP (p+1) st a'
Just (NConstr t as) -> pprec $ "NConstr"
<+> int t
<+> brackets (list $ showNodeAtP 0 st <$> as)
where list = hcat . punctuate ", "
Just NUninitialised -> "<uninitialised>"
Nothing -> errTxtInvalidAddress
where
h = st ^. gmHeap
pprec = maybeParens (p > 0)
showSc :: GmState -> (Name, Addr) -> Doc
showSc st (k,a) = "Supercomb " <> qquotes (textt k) <> colon
$$ code
where
code = case hLookup a (st ^. gmHeap) of
Just (NGlobal _ c) -> showCode c
Just _ -> errTxtInvalidObject
Nothing -> errTxtInvalidAddress
errTxtInvalidObject, errTxtInvalidAddress :: (IsString a) => a
errTxtInvalidObject = "<invalid object>"
errTxtInvalidAddress = "<invalid address>"
showCode :: Code -> Doc
showCode c = "Code" <+> braces instrs
where instrs = vcat $ showInstr <$> c
showInstr :: Instr -> Doc
showInstr (CaseJump alts) = "CaseJump" $$ nest pprTabstop alternatives
where
showAlt (t,c) = "<" <> int t <> ">" <> showCodeShort c
alternatives = foldr (\a acc -> showAlt a $$ acc) mempty alts
showInstr i = text $ show i
textt :: (IsText a) => a -> Doc
textt t = t ^. unpacked & text
----------------------------------------------------------------------------------
showCon :: (IsText a) => Tag -> Int -> a
showCon t n = printf "Pack{%d %d}" t n ^. packed

83
src/GM/Types.hs Normal file
View File

@@ -0,0 +1,83 @@
{-# LANGUAGE TemplateHaskell #-}
module GM.Types where
--------------------------------------------------------------------------------
import Control.Lens.Combinators
import Data.Heap
import Data.Default
import Core.Syntax
--------------------------------------------------------------------------------
data GmState = GmState
{ _gmCode :: Code
, _gmStack :: Stack
, _gmDump :: Dump
, _gmHeap :: GmHeap
, _gmEnv :: Env
, _gmStats :: Stats
}
deriving Show
type Code = [Instr]
type Stack = [Addr]
type Dump = [(Code, Stack)]
type Env = [(Key, Addr)]
type GmHeap = Heap Node
data Key = NameKey Name
| ConstrKey Tag Int
deriving (Show, Eq)
-- >> [ref/Instr]
data Instr = Unwind
| PushGlobal Name
| PushConstr Tag Int
| PushInt Int
| Push Int
| MkAp
| Slide Int
| Update Int
| Pop Int
| Alloc Int
| Eval
-- arith
| Neg | Add | Sub | Mul | Div
-- comparison
| Equals | Lesser | GreaterEq
| Pack Tag Int -- Pack Tag Arity
| CaseJump [(Tag, Code)]
| Split Int
| Print
| Halt
deriving (Show, Eq)
-- << [ref/Instr]
data Node = NNum Int
| NAp Addr Addr
-- NGlobal is the GM equivalent of NSupercomb. rather than storing a
-- template to be instantiated, NGlobal holds the global's arity and
-- the pre-compiled code :3
| NGlobal Int Code
| NInd Addr
| NUninitialised
| NConstr Tag [Addr] -- NConstr Tag Components
| NMarked Node
deriving (Show, Eq)
-- TODO: log executed instructions
data Stats = Stats
{ _stsReductions :: Int
, _stsPrimReductions :: Int
, _stsAllocations :: Int
, _stsDereferences :: Int
, _stsGCCycles :: Int
}
deriving Show
instance Default Stats where
def = Stats 0 0 0 0 0
-- TODO: _gmGlobals should not have a setter
makeLenses ''GmState
makeLenses ''Stats

54
src/GM/Visual.hs Normal file
View File

@@ -0,0 +1,54 @@
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module GM.Visual
( renderGmState
)
where
--------------------------------------------------------------------------------
import Text.Printf
import Data.Function ((&), on)
import Text.PrettyPrint qualified as P
import Diagrams.Prelude
import Diagrams.Backend.Cairo
import GM.Types
import GM.Print
--------------------------------------------------------------------------------
renderGmState :: GmState -> IO ()
renderGmState st = renderCairo path size (drawState st)
where
size = mkSizeSpec2D (Just 1000) (Just 1000)
path = printf "/tmp/render/%04d.png" n
n = st ^. gmStats . stsReductions
drawState :: GmState -> Diagram B
drawState = drawStack
drawStack :: GmState -> Diagram B
drawStack st = st & vcatOf (gmStack . each . to cell)
where
cell a = rect 10 5
<> text (printf "%04x: %s" a (P.render . showNodeAt st $ a))
vcatOf :: (InSpace V2 n a, Floating n, Juxtaposable a, HasOrigin a, Monoid' a)
=> Getting (Endo [a]) s a -> s -> a
vcatOf l = vcat . (^.. l)
newtype Vap a = Vap { getVap :: a }
instance (InSpace V2 n a, Juxtaposable a, Semigroup a)
=> Semigroup (Vap a) where (<>) = (Vap .) . ((===) `on` getVap)
instance (InSpace V2 n a, Juxtaposable a, Monoid a)
=> Monoid (Vap a) where mempty = Vap mempty
newtype Hap a = Hap { getHap :: a }
instance (InSpace V2 n a, Juxtaposable a, Semigroup a)
=> Semigroup (Hap a) where (<>) = (Hap .) . ((|||) `on` getHap)
instance (InSpace V2 n a, Juxtaposable a, Monoid a)
=> Monoid (Hap a) where mempty = Hap mempty