Yuji Yamamoto (山本悠滋)
2019-08-23 HIW 2019
Monad
can do but Applicative
cannot,
and vice versa.(>>=)
with IxState
and
keep your EDSL Monad-free.
Symbol
.IxState
with an extensible
record when executing.Monad
Can Do But Applicative
Cannot>>=
Applicative
Can Do But Monad
CannotSeveral things. Today I focus on:
Applicative
Can Do But Monad
CannotWhy?
Applicative
Can Do But Monad
CannotWhy?
Applicative
Can Do But Monad
CannotWhy?
Monad
can choose which execution paths to go by the
results of the actions, thanks to >>=
.Monad
can’t grasp all
possibly-executed actions.
Applicative
can do that!Applicative
Can Do But Monad
CannotTraversing all paths is useful for…
--help
of the all available options
by traversing them.I want to add some bind-like feature to those
Applicative
s anyway!
(>>=)
with IxApplicative and Extensible
RecordRequired Types etc:
IxApplicative
IxStateT
if you write a monadic interpreter for the EDSL.RebindableSyntax
if you make the EDSL available with
do
syntax.(>>=)
with IxApplicative and Extensible
RecordExample: Not very useful expression language.
(>>=)
with IxApplicative and Extensible
RecordAdd value constructors for Applicative
instance.
(>>=)
with IxApplicative and Extensible
RecordAdd extensible records as type arguments:
data Exp (xs :: [Assoc Symbol Type]) (ys :: [Assoc Symbol Type]) a where
Hask :: a -> Exp xs xs a
Succ :: Exp xs xs Int -> Exp xs xs Int
(:<) :: Exp xs xs Int -> Exp xs xs Int -> Exp xs xs Bool
Fmap :: (a -> b) -> Exp xs ys a -> Exp xs ys b
Ap :: Exp xs ys (a -> b) -> Exp ys zs a -> Exp xs zs b
Then :: Exp xs ys a -> Exp ys zs b -> Exp xs zs b
(>>=)
with IxApplicative and Extensible
RecordAdd extensible records as type arguments:
Exp
is an IxApplicative
IxApplicative
and IxFunctor
.(>>=)
with IxApplicative and Extensible
RecordAdd operators to update associated extensible records:
data Exp (xs :: [Assoc Symbol Type]) (ys :: [Assoc Symbol Type]) a where
-- ...
Let :: KnownSymbol k =>
FieldName k -> Exp xs xs a -> Exp xs (k >: a ': xs) ()
-- ^ Introduce a new variable.
Ref :: (Lookup xs k v, KnownSymbol k) =>
FieldName k -> Exp xs xs v
-- ^ Read an already introduced variable.
(:=) :: (Lookup xs k v, KnownSymbol k) =>
FieldName k -> Exp xs xs v -> Exp xs xs ()
-- ^ Update an already introduced variable.
(>>=)
with IxApplicative and Extensible
RecordAdd more operators to refer the bound variables.
Now I turned a tiny expression EDSL into an imperative EDSL which can update variables.
>>=
operator!Bonus: using RebindableSyntax
run :: Exp '[] ys a -> (a, Record ys)
run = (`runIxState` nil) . toIxState
where
-- ...
toIxState (Let k mx) = toIxState mx >>>= \x -> imodify (k @== x <:)
toIxState (Ref k) = igets (^. itemAssoc (fieldNameToProxy k))
toIxState (k := mx) =
toIxState mx >>>= imodify . set (itemAssoc (fieldNameToProxy k))
toIxState (If cond t f) =
toIxState cond >>>= bool (toIxState f) (toIxState t)
-- ...
Count how many times every variable is referred.
collectStats :: Exp xs ys a -> Map.Map String Int
-- ...
collectStats (Let _ mx) = collectStats mx
collectStats (Ref k) = one k
collectStats (k := mx) = one k `merge` collectStats mx
collectStats (If cond t f) =
collectStats cond `merge` collectStats t `merge` collectStats f
-- ...
merge = Map.unionWith (+)
one k = Map.singleton (symbolVal $ fieldNameToProxy k) 1
Demonstrate here!
I failed to implement in time…😞
IxApplicative
, we can add a bind-like feature to
our DSLs.