{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Generics.MRSOP.Holes where
import Data.Proxy
import Data.Functor.Const
import Data.Type.Equality
import qualified Data.Set as S (insert , empty , Set)
import Control.Monad.Identity
import Control.Monad.State
import Generics.MRSOP.Base
data HolesAnn :: (Atom kon -> *)
-> (kon -> *)
-> [[[Atom kon]]]
-> (Atom kon -> *)
-> Atom kon
-> *
where
Hole :: ann at -> phi at -> HolesAnn ann ki codes phi at
HOpq :: ann ('K k) -> ki k -> HolesAnn ann ki codes phi ('K k)
HPeel :: (IsNat n , IsNat i)
=> ann ('I i)
-> Constr (Lkup i codes) n
-> NP (HolesAnn ann ki codes phi) (Lkup n (Lkup i codes))
-> HolesAnn ann ki codes phi ('I i)
holesAnn :: HolesAnn ann ki codes phi at -> ann at
holesAnn (Hole a _) = a
holesAnn (HOpq a _) = a
holesAnn (HPeel a _ _) = a
holesMapAnnM :: (Monad m)
=> (forall a . f a -> m (g a))
-> (forall a . ann a -> m (bnn a))
-> HolesAnn ann ki codes f at
-> m (HolesAnn bnn ki codes g at)
holesMapAnnM f g (Hole a x) = Hole <$> g a <*> f x
holesMapAnnM _ g (HOpq a k) = flip HOpq k <$> g a
holesMapAnnM f g (HPeel a c p) = g a >>= \a' -> HPeel a' c <$> mapNPM (holesMapAnnM f g) p
holesMapM :: (Monad m)
=> (forall a . f a -> m (g a))
-> HolesAnn ann ki codes f at
-> m (HolesAnn ann ki codes g at)
holesMapM f = holesMapAnnM f return
holesMapAnn :: (forall a . f a -> g a)
-> (forall a . ann a -> ann' a)
-> HolesAnn ann ki codes f at
-> HolesAnn ann' ki codes g at
holesMapAnn f g = runIdentity . holesMapAnnM (return . f) (return . g)
holesMap :: (forall a . f a -> g a)
-> HolesAnn ann ki codes f at
-> HolesAnn ann ki codes g at
holesMap f = holesMapAnn f id
holesJoin :: HolesAnn ann ki codes (HolesAnn ann ki codes f) at
-> HolesAnn ann ki codes f at
holesJoin (Hole _ x) = x
holesJoin (HOpq a k) = HOpq a k
holesJoin (HPeel a c p) = HPeel a c (mapNP holesJoin p)
holesGetHolesAnnWith :: forall f r ann ki codes phi at
. f r
-> (r -> f r -> f r)
-> (forall ix . phi ix -> r)
-> HolesAnn ann ki codes phi at
-> f r
holesGetHolesAnnWith empty ins tr
= flip execState empty . holesMapM getHole
where
getHole :: phi ix
-> State (f r) (phi ix)
getHole x = modify (ins $ tr x) >> return x
holesGetHolesAnnWith' :: (forall ix . phi ix -> r)
-> HolesAnn ann ki codes phi at -> [r]
holesGetHolesAnnWith' = holesGetHolesAnnWith [] (:)
holesGetHolesAnnWith'' :: (Ord r)
=> (forall ix . phi ix -> r)
-> HolesAnn ann ki codes phi at -> S.Set r
holesGetHolesAnnWith'' = holesGetHolesAnnWith S.empty S.insert
holesRefineAnnM :: (Monad m)
=> (forall ix . ann ix -> f ix -> m (HolesAnn ann ki codes g ix))
-> (forall k . ann ('K k) -> ki k -> m (HolesAnn ann ki codes g ('K k)))
-> HolesAnn ann ki codes f at
-> m (HolesAnn ann ki codes g at)
holesRefineAnnM f _ (Hole a x) = f a x
holesRefineAnnM _ g (HOpq a k) = g a k
holesRefineAnnM f g (HPeel a c holesnp)
= HPeel a c <$> mapNPM (holesRefineAnnM f g) holesnp
holesRefineVarsM :: (Monad m)
=> (forall ix . ann ix -> f ix -> m (HolesAnn ann ki codes g ix))
-> HolesAnn ann ki codes f at
-> m (HolesAnn ann ki codes g at)
holesRefineVarsM f = holesRefineAnnM f (\a -> return . HOpq a)
holesRefineAnn :: (forall ix . ann ix -> f ix -> HolesAnn ann ki codes g ix)
-> (forall k . ann ('K k) -> ki k -> HolesAnn ann ki codes g ('K k))
-> HolesAnn ann ki codes f at
-> HolesAnn ann ki codes g at
holesRefineAnn f g = runIdentity . holesRefineAnnM (\a -> return . f a) (\a -> return . g a)
holesAnnCataM :: (Monad m)
=> (forall at . ann at -> phi at -> m (res at))
-> (forall k . ann ('K k) -> ki k -> m (res ('K k)))
-> (forall i n . (IsNat i, IsNat n)
=> ann ('I i) -> Constr (Lkup i codes) n
-> NP res (Lkup n (Lkup i codes))
-> m (res ('I i)))
-> HolesAnn ann ki codes phi ix
-> m (res ix)
holesAnnCataM hF _ _ (Hole a x) = hF a x
holesAnnCataM _ oF _ (HOpq a x) = oF a x
holesAnnCataM hF oF cF (HPeel a c p)
= mapNPM (holesAnnCataM hF oF cF) p >>= cF a c
holesAnnCata :: (forall at . ann at -> phi at -> res at)
-> (forall k . ann ('K k) -> ki k -> res ('K k))
-> (forall i n . (IsNat i, IsNat n)
=> ann ('I i) -> Constr (Lkup i codes) n
-> NP res (Lkup n (Lkup i codes))
-> res ('I i))
-> HolesAnn ann ki codes phi ix
-> res ix
holesAnnCata hF oF cF = runIdentity
. holesAnnCataM (\a phi -> return $ hF a phi)
(\a o -> return $ oF a o)
(\a c p -> return $ cF a c p)
holesSynthesizeM :: (Monad m)
=> (forall at . ann at -> phi at -> m (res at))
-> (forall k . ann ('K k) -> ki k -> m (res ('K k)))
-> (forall i n . (IsNat i, IsNat n)
=> ann ('I i) -> Constr (Lkup i codes) n
-> NP res (Lkup n (Lkup i codes))
-> m (res ('I i)))
-> HolesAnn ann ki codes phi atom
-> m (HolesAnn res ki codes phi atom)
holesSynthesizeM hF oF cF
= holesAnnCataM (\a phi -> flip Hole phi <$> hF a phi)
(\a o -> flip HOpq o <$> oF a o)
(\a c p -> (\r -> HPeel r c p) <$> cF a c (mapNP holesAnn p))
holesSynthesize :: (forall at . ann at -> phi at -> res at)
-> (forall k . ann ('K k) -> ki k -> res ('K k))
-> (forall i n . (IsNat i, IsNat n)
=> ann ('I i) -> Constr (Lkup i codes) n
-> NP res (Lkup n (Lkup i codes))
-> res ('I i))
-> HolesAnn ann ki codes phi ix
-> HolesAnn res ki codes phi ix
holesSynthesize hF oF cF = runIdentity
. holesSynthesizeM (\a phi -> return $ hF a phi)
(\a o -> return $ oF a o)
(\a c p -> return $ cF a c p)
type Holes = HolesAnn (Const ())
pattern Hole' :: phi at -> Holes ki codes phi at
pattern Hole' x = Hole (Const ()) x
pattern HOpq' :: ki k -> Holes ki codes phi ('K k)
pattern HOpq' x = HOpq (Const ()) x
pattern HPeel' :: () => (IsNat n, IsNat i)
=> Constr (Lkup i codes) n
-> NP (Holes ki codes phi) (Lkup n (Lkup i codes))
-> Holes ki codes phi ('I i)
pattern HPeel' c p = HPeel (Const ()) c p
{-# COMPLETE Hole' , HOpq' , HPeel' #-}
holesLCP :: (EqHO ki)
=> Holes ki codes f at
-> Holes ki codes g at
-> Holes ki codes (Holes ki codes f :*: Holes ki codes g) at
holesLCP (HOpq _ kx) (HOpq _ ky)
| eqHO kx ky = HOpq' kx
| otherwise = Hole' (HOpq' kx :*: HOpq' ky)
holesLCP (HPeel a cx px) (HPeel b cy py)
= case testEquality cx cy of
Nothing -> Hole' (HPeel a cx px :*: HPeel b cy py)
Just Refl -> HPeel' cx $ mapNP (uncurry' holesLCP) (zipNP px py)
holesLCP x y = Hole' (x :*: y)
na2holes :: NA ki (Fix ki codes) at -> HolesAnn (Const ()) ki codes f at
na2holes (NA_K k) = HOpq' k
na2holes (NA_I x) = case sop (unFix x) of
Tag cx px -> HPeel' cx (mapNP na2holes px)
holes2naM :: (Monad m)
=> (forall ix . f ix -> m (NA ki (Fix ki codes) ix))
-> Holes ki codes f at
-> m (NA ki (Fix ki codes) at)
holes2naM red (Hole _ x) = red x
holes2naM _ (HOpq _ k) = return (NA_K k)
holes2naM red (HPeel _ c p) = (NA_I . Fix . inj c) <$> mapNPM (holes2naM red) p
holesArity :: HolesAnn ann ki codes f at -> Int
holesArity = length . holesGetHolesAnnWith' (const ())
holesSize :: HolesAnn ann ki codes f at -> Int
holesSize (Hole _ _) = 0
holesSize (HOpq _ _) = 1
holesSize (HPeel _ _ p) = 1 + sum (elimNP holesSize p)
holesSNat :: (IsNat ix)
=> HolesAnn ann ki codes f ('I ix)
-> SNat ix
holesSNat _ = getSNat (Proxy :: Proxy ix)
instance (EqHO phi , EqHO ki) => EqHO (Holes ki codes phi) where
eqHO utx uty = and $ holesGetHolesAnnWith' (uncurry' cmp) $ holesLCP utx uty
where
cmp :: HolesAnn ann ki codes phi at -> HolesAnn ann ki codes phi at -> Bool
cmp (Hole _ x) (Hole _ y) = x `eqHO` y
cmp (HOpq _ x) (HOpq _ y) = x `eqHO` y
cmp _ _ = False
holesShow :: forall ki ann f fam codes ix
. (HasDatatypeInfo ki fam codes , ShowHO ki , ShowHO f)
=> Proxy fam
-> (forall at . ann at -> ShowS)
-> HolesAnn ann ki codes f ix
-> ShowS
holesShow _ f (Hole a x) = ('`':) . f a . showString (showHO x)
holesShow _ f (HOpq a k) = f a . showString (showHO k)
holesShow p f h@(HPeel a c rest)
= showParen (needParens h) $ showString cname
. f a
. showString " "
. withSpaces (elimNP (holesShow p f) rest)
where
withSpaces :: [ShowS] -> ShowS
withSpaces ls = foldl (\r ss -> r . showString " " . ss) id ls
cname = case constrInfoFor p (holesSNat h) c of
(Record name _) -> name
(Constructor name) -> name
(Infix name _ _) -> "(" ++ name ++ ")"
needParens :: HolesAnn ann ki codes f iy -> Bool
needParens (Hole _ _) = False
needParens (HOpq _ _) = False
needParens (HPeel _ _ Nil) = False
needParens _ = True
instance {-# OVERLAPPABLE #-} (HasDatatypeInfo ki fam codes , ShowHO ki , ShowHO f , ShowHO ann)
=> ShowHO (HolesAnn ann ki codes f) where
showHO h = holesShow (Proxy :: Proxy fam) showsAnn h ""
where
showsAnn ann = showString "{"
. showString (showHO ann)
. showString "}"
instance {-# OVERLAPPING #-} (HasDatatypeInfo ki fam codes , ShowHO ki , ShowHO f)
=> Show (Holes ki codes f at) where
show h = holesShow (Proxy :: Proxy fam) (const id) h ""