7 ms·
I have tried writing non-trivial Haskell programs in the past, but the IOMonad/lack of parameterized modules has stifled me. Essentially, I start with basic co
by zohebv 15y ago
I have tried writing non-trivial Haskell programs in the past, but the IOMonad/lack of parameterized modules has stifled me.
Essentially, I start with basic code and possibly use some constants in the beginning. Eventually, I need the constants to be loaded from a config file or command line and now a huge swath of my code, which was perfectly pure, needs to be dragged into the IO Monad and the refactoring effort involved is huge, as no function that is even indirectly touching the so-called constant is now pure. This ends up being extremely painful. I have asked around and 2 suggestions I received, dump all my refactored functions inside a giant let clause, or wait for parameterized modules. How did you deal with this issue?
- dons 15y agoIf your configs become parameters to your app at initialiisation time, you're in the (pure) Reader monad. See xmonad for an example.
- jrockway 15y agoYou pass the data around to the functions that need it, just like you would in any programming language. The simplest case is: do_work :: Config -> Result do_work config = ... read_config :: IO Config main = do config <- read_config print . do_work $ config But you can also put the configuration in a Reader, and avoid the step of manually passing the config to each function that needs it. Instead of: my_program :: Config -> Result step1 :: Config -> Arg -> OneResult step2 :: Config -> Arg -> SecondResult my_program config = step2 config . step1 config You'll write: my_program = runReader config $ do x <- step1 42 return . step2 $ x So let clauses and parameterized modules are not even in the running. Whenever you have a problem in Haskell, the best way to solve it is to ask yourself how you'd solve it in some other language. Then do that. (Nobody writes software in any language where every function is responsible for reading a config file; that functionality is delegated to some common instance that is passed around as needed. So do that in Haskell, too.)
- jrockway 15y agoReading this a day later, there were a couple brainos in there. First, the second argument to step2 should be of type OneResult rather than Arg. Secondly, there is no need for return at the end of my_program, since step1 and step2 are both "in Reader": my_program = do x <- step1 42 step2 x or my_program = step2 =<< step1 42 (I use =<< instead of >>= so that nonadic composition reads like normal composition (.).) Anyway, then do: runReader my_program config
- deleted 15y ago[deleted]