Happstack and Monad Learning Converters

So, I have a project which, it seems to me, is simple enough to learn, but complex enough to be interesting, what I would like to write using the Happstack library. At this very fundamental level, this project will be just a fancy file server with some REST methods for a specific domain (or something else, I don’t care whether it is RESTful or not) to search and retrieve the specified files and metadata. Since I am also trying to really learn monad transformers right now, I decided that it would be a great project to learn from. However, I encountered some difficulties when it started, especially with how to build my transformer stack.

Currently, only a few things bother me: the config, error report and status, as well as logging, so I started with

newtype MyApp a = MyApp { runMyApp :: ReaderT Config (ErrorT String (StateT AppState IO)) a } deriving (...) 

Since I will always be in IO, I can easily use hslogger to do this to take care of my logging. But I also knew that I needed to use ServerPartT to interact with Happstack, this way

 runMyApp :: ReaderT Config (ErrorT String (StateT AppState (ServerPartT IO))) a 

I can get this to run, see requests, etc., but the problem I am facing is that it requires FilterMonad to use methods like dir , path and ok , but I have no idea how implement it for this type. I just need to pass the filters down to the main monad. Can someone give me some guidance on how to implement this obviously important class of types? Or, if I'm just doing something terrible, just direct me in the right direction. I only looked at Happstack for a few days, and the transformers are still new to me. I think I understand them enough to be dangerous, but I don’t know enough about them so that I can implement it myself. Any help you can provide is greatly appreciated!

FULL CODE

(X-sent from / r / haskell )

+4
source share
1 answer

The easiest thing for you is to get rid of ErrorT from your stack. If you look here , you will see that Happstack defines built-in end-to-end FilterMonad instances for StateT and ReaderT, but there are none for ErrorT. If you really want to keep ErrorT in your stack, you need to write a passthrough instance for it. It will probably look like a ReaderT file.

 instance (FilterMonad res m) => FilterMonad res (ReaderT rm) where setFilter f = lift $ setFilter f composeFilter = lift . composeFilter getFilter = mapReaderT getFilter 

I am inclined to think that you should not have ErrorT baked in your application monad, because you will not always have to deal with calculations that may fail. If you need to handle a failure in a section of your code, you can always easily get into it by simply wrapping runErrorT around the section and then using ErrorT , lift and return as needed. In addition, an extra level in your transformer stack adds a performance tax for each binding. Thus, although the composition of monodal transformers is really good, you usually want to use them sparingly when performance is an important factor.

In addition, I would recommend using EitherT instead of ErrorT. This way you can use the fantastic bug package . It has many really common handy features like hush , just etc.

Also, if you want to see a real example of what you're trying to do, take a look at Snap Handad monad . MoA MyApp - this is exactly the problem that was resolved to solve. The processor has some additional complexity because it was designed to solve the problem in a generalized way, so Snap users would not need to build this common transformer stack on their own. But if you look at the basic implementation , you will see that at its core it is really just Reader and State monads, condensed into one.

+1
source

Source: https://habr.com/ru/post/1488412/


All Articles