emilypi / smash

Smash products, Wedge products, and other Pointed stuff

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Monad Transformers for `smash-core`

emilypi opened this issue · comments

transformers and mtl are bundled with GHC, so this is a zero-cost addition to the library.

I'm not sure I can help, but I'm curious: for transformers, does this mean something like adding a module named Control.Monad.Trans.Smash with stuff like:

newtype SmashT m a b = SmashT { runSmashT :: m (Smash a b) }

instance Functor m => Functor (SmashT m a) where
  fmap f = SmashT . fmap (fmap f) . runSmashT

instance (Monoid a, Applicative m) => Applicative (SmashT m a) where
  pure = SmashT . pure . Smash mempty
  f <*> x =
    let fsm = runSmashT f
        xsm = runSmashT x
     in SmashT $ (<*>) <$> fsm <*> xsm

instance (Monoid a, Monad m) => Monad (SmashT m a) where
  x >>= f = SmashT $ do
    sm <- runSmashT x
    case sm of
      Nada -> return Nada
      Smash a b -> do
        sm' <- runSmashT (f b)
        case sm' of
          Nada -> return Nada
          Smash a' b' -> return $ Smash (a `mappend` a') b'

...plus all the usual instances for MonadTrans, etc.?

Also, for mtl, would Smash, for example, have an instance for MonadError? Would there be any others? I'm sorta lacking an intuition for what the types in this library can model: it seems to me like Smash a b can be used like WriterT a (MaybeT Identity) b as a writer that may fail; would this be a usual usage?

does this mean something like adding a module...

Yes! that's all it means.

MonadError

I think this would probably be the only genuinely useful one, and they should all have this instance because they're all something isomorphic to Maybe <thing>. All of the dataypes in the library satisfy this instance I think. I'd have to look into MonadReader, MonadWriter and MonadState as well. We can work on this together if you'd like.

would this be a usual usage?

this is a little more thought than I've put into the Writer instances, but just off the top of my head I think this would break down like so:

-- where SmashT a m b ~ m (Smash a b)
t ~ () => WriterT w (SmashT t Identity) a
~ (SmashT t Identity) (a, w)
~ Identity (Smash t (a, w))
~ Smash t (a, w)
-- Smash t (a, w) ~ Maybe (t, (a, w)) ~ Maybe (a, w) ~ Smash a w
~ Smash a w
~ Maybe (a, w)
~ MaybeT Identity (a, w)
~ WriterT w (MaybeT Identity) a

Which is a little unsatisfying, but works nonetheless. So we're left with a bit of a weird instance here. I would expect the failure mode to be the Nothing case of the Maybe (w, a) tuple, but we clearly have a () here that could also serve as a no-op or failure mode.

I'll give a try at helping out. What nixpkgs/nixos version(s) are you guys using to test?

I'm not using any nix infra to test any of these packages - it's purely travis. this is because I'm not a Nix person, and I use a very dumb tool called cabal2nix to nixify my packages for the nix folks. If you have a better or more competent way, I am all ears 😄

Closed via #25