Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 9034589
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 16, 20262026-06-16T08:31:29+00:00 2026-06-16T08:31:29+00:00

This is going to be a long one because I’m not sure that I

  • 0

This is going to be a long one because I’m not sure that I went into this in the right frame of mind, so I’m going to outline my thinking as clearly as possible at each step of the way. I’ve got two code snippets that are about as minimal as I can make them, so feel free to use those.

I started with a single transformer FitStateT m a, which just holds the state of the program at the time and allowed saving to disk:

data FitState = FitState
newtype FitStateT m a = FitStateT (StateT FitState m a) deriving (Monad, MonadTrans)

At some point further into the project I decided to add haskeline into the project which has some datatypes likes this:

-- Stuff from haskeline.  MonadException is something that haskeline requires for whatever reason.
class MonadIO m => MonadException m
newtype InputT m a = InputT (m a) deriving (Monad, MonadIO)

So my routines in my main file would look something like this:

myMainRoutineFunc :: (MonadException m, MonadIO m) => FitStateT (InputT m) ()
myMainRoutineFunc = do
  myFitStateFunc
  lift $ myInputFunc
  return ()

Unfortunately there were a number of problems with this as my program grew. The main problem was that for every input function I ran, I had to lift before I ran it. The other problem is for every function that ran an input command, I required a MonadException m constraint on it. Also for any function that ran a fitstate related function it required a MonadIO m constraint on it.

Here’s the code: https://gist.github.com/4364920

So I decided to create some classes to make this fit together a little better and to clean up the types a little. My goal is to be able to write something like this:

myMainRoutineFunc :: (MonadInput t m, MonadFitState t m) => t m ()
myMainRoutineFunc = do
  myFitStateFunc
  myInputFunc
  return ()

First I created a MonadInput class to wrap around the InputT type and then my own routine would just become an instance of this class.

-- Stuff from haskeline.  MonadException is something that haskeline requires for whatever reason.
class MonadIO m => MonadException m
newtype InputT m a = InputT (m a) deriving (Monad, MonadIO)

-- So I add a new class MonadInput
class MonadException m => MonadInput t m where
  liftInput :: InputT m a -> t m a

instance MonadException m => MonadInput InputT m where
  liftInput = id

I added the MonadException constraint so that I would not have to specify it separately on every input related function. This necessitated adding multiparamtypeclasses and flexibleinstances, but the resulting code was exactly what I was looking for:

myInputFunc :: MonadInput t m => t m (Maybe String)
myInputFunc = liftInput $ undefined

So then I did the same for FitState. Again I added the MonadIO constraint:

-- Stuff from my own transformer.  This requires that m be MonadIO because it needs to store state to disk
data FitState = FitState
newtype FitStateT m a = FitStateT (StateT FitState m a) deriving (Monad, MonadTrans, MonadIO)

class MonadIO m => MonadFitState t m where
  liftFitState :: FitStateT m a -> t m a

instance MonadIO m => MonadFitState FitStateT m where
  liftFitState = id

Which again works perfectly.

myFitStateFunc :: MonadFitState t m => t m ()
myFitStateFunc = liftFitState $ undefined

And then I wrapped my main routine into a newtype wrapper so that I could create instances of these two classes:

newtype Routine m a = Routine (FitStateT (InputT m) a)
  deriving (Monad, MonadIO)

And then an instance of MonadInput:

instance MonadException m => MonadInput Routine m where
  liftInput = Routine . lift

Works perfectly. Now for MonadFitState:

instance MonadIO m => MonadFitState Routine m where
  liftFitState = undefined
--  liftFitState = Routine -- This fails with an error.

Ah crap, it fails.

Couldn't match type `m' with `InputT m'
  `m' is a rigid type variable bound by
      the instance declaration at Stack2.hs:43:18
Expected type: FitStateT m a -> Routine m a
  Actual type: FitStateT (InputT m) a -> Routine m a
In the expression: Routine
In an equation for `liftFitState': liftFitState = Routine

And I don’t know what to do to make this work. I don’t really understand the error. Does it mean I have to make FitStateT an instance of MonadInput? That seems really weird, those are two completely different modules with nothing in common. Any help would be appreciated. Is there a better way to get what I’m looking for?

Completed code with error: https://gist.github.com/4365046

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-16T08:31:30+00:00Added an answer on June 16, 2026 at 8:31 am

    Well, to start with, here’s the type of liftFitState:

    liftFitState :: MonadFitState t m => FitStateT m a -> t m a
    

    And here’s the type of Routine:

    Routine :: FitStateT (InputT m) a -> Routine m a
    

    Your liftFitState function expects a single wrapper type to be converted from FitStateT, but Routine has two layers of transformer it wraps. So the types won’t match up.

    Beyond that, I really suspect you’re going about this the wrong way.

    First of all, if you’re writing an application, not a library, it’s more common to simply wrap all the monad transformers you need in one big stack and use that everywhere. Typically the only reason for leaving it as a transformer would be for switching between a limited number of base monads, e.g. Identity, IO, ST, or STM. But even that’s overkill if everything you need your transformer stack for requires IO and you’re not intending to use ST or STM.

    In your case the simplest approach would apparently look something like this:

    newtype App a = App { getApp :: StateT FitState (InputT IO) a }
    

    …then derive or manually implement the MonadFoo classes you want (e.g. MonadIO), and simply use that stack everywhere.

    The benefit of doing it this way, instead of mucking about with multiple layers, is that later on if you need to add another transformer the way you added Haskeline–deciding to add a ReaderT for some sort of global data resources, say–you can simply add it to the wrapped stack and all the code currently using the stack won’t even know the difference.


    On the other hand, if you really do want to take your current approach, you’re getting the monad transformer lifting idiom a bit wrong. The basic lifting operation should come from MonadTrans, which you’re already deriving. MonadFoo classes are generally for providing the essential operations for each monad generically, e.g. get and put for MonadState.

    You seem to be trying to imitate liftIO, which is a “lift all the way” operation to lift enough times to get from the bottom of the stack–IO–to the actual monad. This doesn’t really make sense for transformers that can appear anywhere in a stack.

    If you do want to have your own MonadFoo classes, I suggest looking at the source for classes like MonadState and seeing how they work, then following the same pattern.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Ok saddle up cowboys, because this is going to be a long one. I
I'm 100% sure this is going to be one of those newbie questions, but
This is going to be a long post and just for fun, so if
This is going to sound too silly / too basic - sorry about that,
Hey this is going to be one of those dumb questions. I am trying
I think this is going to be one of those simple-when-you-see-it problems, but it
I know this is going to be something simple that I'm just missing somehow,
This is going to be a little long and rambly, but I want to
I'm going to ask and answer this question because it took me forever to
that's going to be a long question so bear with me :) My Application

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.