List DSL and ergonomics - Polysemy

Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.

Sridhar Ratnakumar

This may be a strange question. I have the following DSL whose sole purpose is to construct a list, and as such as it provides one method that will append to a being-constructed list:

type X f = DSum f Identity
data XListLang (f :: Type -> Type) m a where
  AddX :: X f -> XListLang f m ()

I use it like this:

xlist :: Sem '[XListLang f] a -> [X f]
xlist = ...

foo = xlist do
  addX thing1
  addX thing2

Question: can that addX be obviated entirely? So that I can define foo as:

foo = xlist do
  thing1
  thing2
Sridhar Ratnakumar

Real-world example:

foodsEaten =  xlist do
  addX $ Coffee :/ 3
  addX $ Cheese :/ Cheddar
  addX $ palette Eumatimi
Sridhar Ratnakumar

(For a larger context, I actually have a "XMapLang" as well - which is all part of of the typed-forest thing described here: https://funprog.srid.ca/haskell/typed-forest.html )

I'm working on the notion of (for lack of better term) "typed forests" - which is a forest type (a tree with several roots) in which each node "determines" its children types (so, dependent types?). I use GADTs to represent the node types. Each GADT constructor represents the possible choice for a n
Sridhar Ratnakumar

For XMapLang this is not a problem, as its methods take two arguments - so I created nice operators:

  Day 9 /> do
    SkinCondition /. Neutral
    Note /+ Note_Highlight :/ [str|No spices whatsoever from this point. Salt only.|]
    Meals /. 1
    Consumed /- do
      addX $ Coffee :/ 3
      addX cheese
      addX $ palette Eumatimi

As you can see, XListLang's method takes one parameter only; so defining operator won't work.

Sridhar Ratnakumar

Currently trying to write a Monad instance myself:

type X f = DSum f Identity

newtype XMonad f a = XMonad {unXMonad :: Sem '[XListLang f] a}

instance Functor (XMonad f) where
  fmap f (XMonad x) = XMonad $ fmap f x

instance Applicative (XMonad f) where
  pure a = XMonad $ pure a
  XMonad f <*> XMonad a = XMonad $ f <*> a

instance Monad (XMonad f) where
  XMonad a >>= f = XMonad $ do
    ???
Sridhar Ratnakumar

Uhh, no. What I need is a monad instance for X f itself.

Sridhar Ratnakumar

But the confusion is: what should be the semantics of stuff <- cheese be? That makes no sense.

Sridhar Ratnakumar

Using PostfixOperators

  Day 9 /> do
    SkinCondition /. Neutral
    Note
      /| (Note_Highlight :/ [str|No spices whatsoever from this point. Salt only.|] /+)
    Consumed
      /| (Coffee :/ 3 /+)
      >> (cheese /+)
      >> (palette Eumatimi /+)
    Meals /. 1

Don't really like those parenthesis though

Sridhar Ratnakumar

Alternatively using list constructor:

    Consumed
      /. Coffee :/ 3
      : cheese
      : (palette Eumatimi)
      : []
    Meals /. 1

But don't like the : [] at the end.

Sridhar Ratnakumar

But I don't like non-do based solutions, because you can't nest the structure without tripping precedences or using paranthesis

Sridhar Ratnakumar

So back to monads, but because Haskell does not allow user-defined unary operators, we use o :: () to:

    Consumed /| do
      o /- Coffee :/ 3
      o /- cheese
      o /- palette Eumatimi
    Meals /. 1
TheMatten

That's very similar to that html-do problem - you could use RebindableSyntax and overload >>, but I guess in this case, you could just as well ditch do for (/-) :: Member (XListLang f) r => X f -> Sem r a -> Sem r ()