Skip to content

Instantly share code, notes, and snippets.

@xgrommx
Created September 10, 2019 14:13
Show Gist options
  • Save xgrommx/7934ef583dd99cb41adde744f4180cd3 to your computer and use it in GitHub Desktop.
Save xgrommx/7934ef583dd99cb41adde744f4180cd3 to your computer and use it in GitHub Desktop.
EADT with profunctor lenses and prisms
module Main where
import Prelude
import Control.Lazy (fix)
import Control.MonadZero (guard, (<|>))
import Data.Foldable (oneOfMap)
import Data.Functor.Mu (Mu, roll, unroll)
import Data.Functor.Variant (VariantF)
import Data.Functor.Variant as VF
import Data.Maybe (Maybe(..), maybe)
import Data.Profunctor (dimap)
import Data.Symbol (class IsSymbol)
import Data.Traversable (class Foldable, class Traversable, foldlDefault, foldrDefault, oneOf, sequenceDefault, traverse)
import Data.Lens (AnIso, Iso, Prism', Traversal', iso, over, prism', re, wander, withIso, (^.), (^?))
import Data.Tuple (Tuple(..), uncurry)
import Effect (Effect)
import Effect.Console (log)
import Matryoshka (Algebra, CoalgebraM, cata, traverseR)
import Prim.Row as Row
import Type.Equality (class TypeEquals)
import Type.Equality as TE
transformOf forall a b. ((a -> b) -> a -> b) -> (b -> b) -> a -> b
transformOf = fix (\r l f x -> f (over l (r l f) x))
rewriteOf forall a b. ((a -> b) -> a -> b) -> (b -> Maybe a) -> a -> b
rewriteOf = fix (\r l f -> transformOf l (\v -> maybe v (r l f) (f v)))
from forall s t a b. AnIso s t a b -> Iso b a t s
from l = withIso l $ \ sa bt -> iso bt sa
type RowApply (f ∷ # Type -> # Type) (a ∷ # Type) = f a
infixr 0 type RowApply as +
type EADT t = Mu (VariantF t)
injEADT
forall f s a b
. Row.Cons s (VF.FProxy f) a b
=> IsSymbol s
=> Functor f
=> VF.SProxy s
-> Algebra f (EADT b)
injEADT label = roll <<< VF.inj label
prjEADT
:: forall f s a b
. Row.Cons s (VF.FProxy f) a b
=> IsSymbol s
=> Functor f
=> VF.SProxy s
-> CoalgebraM Maybe f (EADT b)
prjEADT label = VF.prj label <<< unroll
_VariantF
forall l f v a
. IsSymbol l
=> Functor f
=> Row.Cons l (VF.FProxy f) _ v
=> VF.SProxy l
-> Prism' (VF.VariantF v a) (f a)
_VariantF l = prism' (VF.inj l) (VF.prj l)
_EADT
:: forall l f v
. Row.Cons l (VF.FProxy f) _ v
=> IsSymbol l
=> Functor f
=> VF.SProxy l
-> Prism' (EADT v) (f (EADT v))
_EADT l = prism' (injEADT l) (prjEADT l)
plateMu forall f. Traversable f => Traversal' (Mu f) (Mu f)
plateMu = wander go where
go forall g. Applicative g => (Mu f -> g (Mu f)) -> Mu f -> g (Mu f)
go = traverseR <<< traverse
data ValF a = ValF Int
derive instance functorValFFunctor ValF
instance foldableValF :: Foldable ValF where
foldl f z (ValF a) = z
foldr f z (ValF a) = z
foldMap f _ = mempty
instance traversableValF :: Traversable ValF where
sequence = sequenceDefault
traverse f (ValF a) = pure (ValF a)
data AddF a = AddF a a
derive instance functorAddFFunctor AddF
instance foldableAddF :: Foldable AddF where
foldl f z (AddF a b) = f (f z a) b
foldr f z (AddF a b) = f a (f b z)
foldMap f (AddF a b) = f a <> f b
instance traversableAddF :: Traversable AddF where
sequence = sequenceDefault
traverse f (AddF a b) = AddF <$> f a <*> f b
data MulF a = MulF a a
derive instance functorMulFFunctor MulF
instance foldableMulF :: Foldable MulF where
foldl f = foldlDefault f
foldr f = foldrDefault f
foldMap f (MulF a b) = f a <> f b
instance traversableMulF :: Traversable MulF where
sequence = sequenceDefault
traverse f (MulF a b) = MulF <$> f a <*> f b
data AnnF a e = AnnF a e
derive instance functorAnnFFunctor (AnnF a)
type Val r = (val VF.FProxy ValF | r)
type Add r = (add VF.FProxy AddF | r)
type Mul r = (mul VF.FProxy MulF | r)
type Ann a r = (ann VF.FProxy (AnnF a) | r)
type BaseExpr r = Val + Add + r
_val = VF.SProxy _ "val"
_add = VF.SProxy _ "add"
_mul = VF.SProxy _ "mul"
_ann = VF.SProxy _ "ann"
_Mu forall f g. Iso (f (Mu f)) (g (Mu g)) (Mu f) (Mu g)
_Mu = iso roll unroll
class AsValF s a | s -> a where
_ValF Prism' s Int
instance asValFValFAsValF (ValF a) a where
_ValF = prism' ValF (\(ValF a) -> Just a)
else instance asValFVariant :: (Functor f, AsValF (f a) a, TypeEquals (VariantF ( val :: VF.FProxy f | tail ) a) (VariantF row a)) => AsValF (VariantF row a) a where
_ValF = dimap TE.from TE.to <<< _VariantF _val <<< _ValF
else instance asValFFMu :: (Functor f, AsValF (f (Mu f)) a) => AsValF (Mu f) a where
_ValF = re _Mu <<< _ValF
----------------------------------------------------------------
class AsAddF s a | s -> a where
_AddF Prism' s (Tuple a a)
instance asAddFAddFAsAddF (AddF a) a where
_AddF = prism' (uncurry AddF) (\(AddF a b) -> Just (Tuple a b))
else instance asAddFVariant :: (Functor f, AsAddF (f a) a, TypeEquals (VariantF ( add :: VF.FProxy f | tail ) a) (VariantF row a)) => AsAddF (VariantF row a) a where
_AddF = dimap TE.from TE.to <<< _VariantF _add <<< _AddF
else instance asAddFMu :: (Functor f, AsAddF (f (Mu f)) a) => AsAddF (Mu f) a where
_AddF = re _Mu <<< _AddF
----------------------------------------------------------------
class AsMulF s a | s -> a where
_MulF Prism' s (Tuple a a)
instance asMulFMulFAsMulF (MulF a) a where
_MulF = prism' (uncurry MulF) (\(MulF a b) -> Just (Tuple a b))
else instance asMulFVariant :: (Functor f, AsMulF (f a) a, TypeEquals (VariantF ( mul :: VF.FProxy f | tail ) a) (VariantF row a)) => AsMulF (VariantF row a) a where
_MulF = dimap TE.from TE.to <<< _VariantF _mul <<< _MulF
else instance asMulFMu :: (Functor f, AsMulF (f (Mu f)) a) => AsMulF (Mu f) a where
_MulF = re _Mu <<< _MulF
val forall r. Int -> EADT (Val r)
val v = v ^. re _ValF
add forall r. EADT (Add + r) -> EADT (Add + r) -> EADT (Add + r)
add x y = Tuple x y ^. re _AddF
mul forall r. EADT (Mul + r) -> EADT (Mul + r) -> EADT (Mul + r)
mul x y = Tuple x y ^. re _MulF
optimize :: forall m. Traversable m => Array (Mu m -> Maybe (Mu m)) -> Mu m -> Mu m
optimize = rewriteOf plateMu <<< flip (oneOfMap <<< (#))
---- Optimizations
elimPlusZero :: forall r. EADT (Add + Val + r) -> Maybe (EADT (Add + Val + r))
elimPlusZero m = do
Tuple x y <- m ^? _AddF
y <$ is0 x <|> x <$ is0 y
where
is0 v = guard <<< (_ == 0) =<< v ^? _ValF
elimMulZero :: forall r. EADT (BaseExpr + Mul + r) -> Maybe (EADT (BaseExpr + Mul + r))
elimMulZero m = do
Tuple x y <- m ^? _MulF
val 0 <$ is0 x <|> val 0 <$ is0 y
where
is0 v = guard <<< (_ == 0) =<< v ^? _ValF
distr forall r. EADT (Add + Mul + r) -> Maybe (EADT (Add + Mul + r))
distr m = do
Tuple a b <- m ^? _MulF
oneOf [ do
Tuple c d <- b ^? _AddF
pure $ add (mul a c) (mul a d)
, do
Tuple c d <- a ^? _AddF
pure $ add (mul b c) (mul b d)
]
---- Algebras
exprAlg forall r. Algebra (VariantF r) Int -> Algebra (VariantF (BaseExpr + r)) Int
exprAlg = VF.onMatch
{ val: case _ of ValF x -> x
, add: case _ of AddF x y -> x + y }
exprAlg2 forall r. Algebra (VariantF r) Int -> Algebra (VariantF (BaseExpr + Mul + r)) Int
exprAlg2 = exprAlg
>>> VF.on _mul case _ of MulF x y -> x * y
exprShowAlg forall r. Algebra (VariantF r) String -> Algebra (VariantF (BaseExpr + r)) String
exprShowAlg = VF.onMatch
{ val: case _ of ValF x -> show x
, add: case _ of AddF x y -> "(" <> x <> " + " <> y <> ")" }
exprShowAlg2 forall r. Algebra (VariantF r) String -> Algebra (VariantF (BaseExpr + Mul + r)) String
exprShowAlg2 = exprShowAlg
>>> VF.on _mul case _ of MulF x y -> "(" <> x <> " * " <> y <> ")"
expr3 EADT (Val + Add + Mul + ())
expr3 = mul (add (val 10) (val 20)) (add (val 30) (val 40))
expr4 EADT (Val + Add + Mul + ())
expr4 = add (mul (add (val 10) (val 0)) (add (val 30) (mul (val 40) (val 0)))) (val 10)
main :: Effect Unit
main = do
log $ cata (VF.case_ # exprShowAlg2) expr4
log $ cata (VF.case_ # exprShowAlg2) $ optimize [elimMulZero, elimPlusZero] expr4
log "----------------------------------------------------------------"
log $ cata (VF.case_ # exprShowAlg2) expr3
log $ cata (VF.case_ # exprShowAlg2) $ optimize [distr] expr3
log "----------------------------------------------------------------"
log $ cata (VF.case_ # exprShowAlg2) expr3
log $ cata (VF.case_ # exprShowAlg2) $ optimize [distr] expr3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment