Yuji Yamamoto (山本悠滋)

2019-08-23 HIW 2019

- Yuji Yamamoto (@igrep)
- Software Developer at IIJ Innovation Institute, Inc. 😄
- One of the founders of Japan Haskell User Group (a.k.a. Haskell-jp)

- What
`Monad`

can do but`Applicative`

cannot, and vice versa. - Simulate bind
`(>>=)`

with`IxState`

and keep your EDSL Monad-free.- Represent reference to (the result of) an action by
`Symbol`

. - Interpret the actions as
`IxState`

with an extensible record when executing.

- Represent reference to (the result of) an action by
- Example: Tiny EDSL with a monadic interpreter and a static analyzer.

`Monad`

Can Do But `Applicative`

Cannot- Bind
`>>=`

`Applicative`

Can Do But `Monad`

CannotSeveral things. Today I focus on:

- Traverse all execution paths!

`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`>>=`

.- In other words,
`Monad`

can’t grasp**all possibly-executed actions**.- But
`Applicative`

can do that!

- But

`Applicative`

Can Do But `Monad`

CannotTraversing all paths is useful for…

- optparse-applicative:
- Generate
`--help`

of the*all*available options by traversing them.

- Generate
- regex-applicative (Regex as an EDSL in Haskell):
- Compile
*all*operations of a regular expression into an NFA by traversing them.

- Compile

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.- Some extensible record library.
- Here I use extensible package.

`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:

- Now,
`Exp`

is an`IxApplicative`

- Then the value constructors below stand for operators of
`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.

- Add type arguments of extensible records to represent
*the namespace*.- Invalid variable references are statically detected thanks to extensible records.

- Add operators to define/read/update variables.
- Add operators to use the actual value of variables.
- Actually we have to define operators for each one that requires to use the actual value of variables.

- Even with the feature, the expressions can be composed
**only with Applicative APIs**. - No bind
`>>=`

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…😞

- Back reference for regex-applicative.
- EDSL with pretty-printer and interpreter.
- Requires restricted indexed Applicative instead of the standard indexed Applicative. Because not arbitrary Haskell functions can be printed.

- All of these can be implemented by traversing all execution path of the EDSL!

- With
`IxApplicative`

, we can add a bind-like feature to our DSLs. - Even with the bind-like feature, the EDSL still have
**execution path entirely traversable**.