{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TypeOperators #-}
module Data.Comp.Fixplate
(
Eq1, EqF (..)
, Show1, ShowF (..)
, deriveEq1
, deriveShow1
, defaultEqualF
, defaultShowsPrecF
, eqMod
, Term
, pattern Term
, unTerm
, (:&:)
, pattern (:&:)
, (:+:) (..)
, (:<:) (..)
, inject
, project
, HideInj
, showTerm
, showTermU
, drawTerm
, drawTermU
, (.:)
, (.:.)
, (.::)
, (.::.)
, (.:::)
) where
import Data.Composition ((.:), (.:.), (.::), (.::.), (.:::))
import Data.Eq.Deriving (deriveEq1)
import Data.Foldable (toList)
import Data.Functor.Classes (Eq1 (..), Show1 (..), eq1, showsPrec1)
import Data.Generics.Fixplate.Base
( Ann(..)
, EqF(..)
, Hole(..)
, Mu(..)
, ShowF(..)
, showF
)
import qualified Data.Generics.Fixplate.Draw as Fixplate
import Data.Generics.Fixplate.Functor ((:+:) (..))
import Data.Generics.Fixplate.Morphisms (cata)
import Data.Generics.Fixplate.Traversals (restructure)
import Data.Tree (Tree (..))
import qualified Data.Tree.View as TreeView
import Text.Show.Deriving (deriveShow1)
defaultEqualF :: (Eq1 f, Eq a) => f a -> f a -> Bool
defaultEqualF = eq1
defaultShowsPrecF :: (Show1 f, Show a) => Int -> f a -> ShowS
defaultShowsPrecF = showsPrec1
eqMod :: (EqF f, Functor f, Foldable f) => f a -> f b -> Maybe [(a, b)]
eqMod t u
| fmap (const ()) t `equalF` fmap (const ()) u = Just args
| otherwise = Nothing
where
args = toList t `zip` toList u
type Term = Mu
pattern Term :: f (Term f) -> Term f
pattern Term f = Fix f
unTerm :: Term f -> f (Term f)
unTerm (Term f) = f
type f :&: a = Ann f a
pattern (:&:) :: f b -> a -> (f :&: a) b
pattern f :&: a = Ann a f
class f :<: g where
inj :: f a -> g a
prj :: g a -> Maybe (f a)
infix 7 :<:
instance {-# OVERLAPPABLE #-} f :<: f where
inj = id
prj = Just
instance {-# OVERLAPPING #-} f :<: f => f :<: (g :+: f) where
inj = InR
prj (InL _) = Nothing
prj (InR f) = Just f
instance {-# OVERLAPS #-} f :<: h => f :<: (h :+: g) where
inj = InL . inj
prj (InL h) = prj h
prj (InR _) = Nothing
inject :: f :<: g => f (Term g) -> Term g
inject = Fix . inj
project :: f :<: g => Term g -> Maybe (f (Term g))
project = prj . unTerm
toTree :: (Functor f, Foldable f) => Term f -> Tree (f Hole)
toTree = cata $ \f -> Node (const Hole <$> f) $ toList f
newtype HideInj f a = HideInj {unHideInj :: f a}
deriving (Foldable, Functor, Traversable)
instance {-# OVERLAPPABLE #-} ShowF f => ShowF (HideInj f) where
showsPrecF p = showsPrecF p . unHideInj
instance {-# OVERLAPPING #-} (ShowF (HideInj f), ShowF (HideInj g)) =>
ShowF (HideInj (f :+: g)) where
showsPrecF p (HideInj (InL f)) = showsPrecF p (HideInj f)
showsPrecF p (HideInj (InR g)) = showsPrecF p (HideInj g)
data Hole' = Hole'
instance Show Hole' where
show Hole' = "_"
showTerm :: (Functor f, Foldable f, ShowF (HideInj f)) => Term f -> String
showTerm = Fixplate.showTree . restructure HideInj
showTermU :: (Functor f, Foldable f, ShowF (HideInj f)) => Term f -> String
showTermU =
TreeView.showTree . fmap (showF . HideInj . fmap (const Hole')) . toTree
drawTerm :: (Functor f, Foldable f, ShowF (HideInj f)) => Term f -> IO ()
drawTerm = Fixplate.drawTree . restructure HideInj
drawTermU :: (Functor f, Foldable f, ShowF (HideInj f)) => Term f -> IO ()
drawTermU = putStrLn . showTermU