emilypi / smash

Smash products, Wedge products, and other Pointed stuff
34 stars 11 forks source link

Monad Transformers for `smash-core` #7

Closed emilypi closed 3 years ago

emilypi commented 4 years ago

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

darcykimball commented 4 years ago

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?

emilypi commented 4 years ago

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.

darcykimball commented 4 years ago

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

emilypi commented 4 years ago

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 😄

emilypi commented 3 years ago

Closed via #25