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
Applicatives anyway!
(>>=) with IxApplicative and Extensible
RecordRequired Types etc:
IxApplicativeIxStateT
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 IxApplicativeIxApplicative 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) 1Demonstrate here!
I failed to implement in time…😞
IxApplicative, we can add a bind-like feature to
our DSLs.