3 ms·
I previously agreed with complaints #1 and #2, though at some point over the last few years this has stopped being a problem. It's not even Stockholm syndrome,
by enigmo 13y ago
I previously agreed with complaints #1 and #2, though at some point over the last few years this has stopped being a problem. It's not even Stockholm syndrome, I just don't use records that much anymore. The various lens packages can help with record overloading and dot indexed fields, but without some compiler support it will remain a sore spot for people who want/need a better record system.
#5 is a fair to a point. I don't find MPTC or existential types to be useful in almost any case: I actively try to avoid both. ScopedTypeVariables, FlexibleContexts, FlexibleInstances and potentially RankNTypes and the poorly named UndecidableInstances should be standard though (imo). Some people also find OverlappingInstances and the like to be generally useful but you probably don't want to hear what I'd say about the subject.
There are plenty of other (also subjectively ugly) ways to write #3. SHE (a Haskell preprocessor) deals with it in one way, see the pigworker's idiom brackets: https://personal.cis.strath.ac.uk/conor.mcbride/pub/she/idiom.html https://personal.cis.strath.ac.uk/conor.mcbride/pub/she/idio.... Without a preprocessor you can certainly use applicatives or some regular monad combinators to git'r'done but a little sugar could go a long ways. I'm not attached to any of these.
Lucky for us there are many languages to choose from, personal taste has proven a fickle mistress.
import Control.Applicative
import Control.Monad
data ConfigData
data DbConnection
readConfigData :: IO ConfigData
readConfigData = undefined
openDbConnection :: ConfigData -> IO DbConnection
openDbConnection = undefined
openDbConnection2 :: ConfigData -> ConfigData -> IO DbConnection
openDbConnection2 = undefined
openDbConnection3 :: ConfigData -> ConfigData -> ConfigData -> IO DbConnection
openDbConnection3 = undefined
main :: IO ()
main = do
-- it does work...
conf <- readConfigData
_c0 <- openDbConnection conf
-- how about a flipped bind?
_c1 <- openDbConnection =<< readConfigData
-- or join/fmap...
_c2 <- join $ openDbConnection <$> readConfigData
-- need two parameters? liftA2/liftM2 has been around for a while
_c3 <- join $ liftA2 openDbConnection2 readConfigData readConfigData
-- or use Functor/Applicative to deal with arbitrary numbers of side effecting parameters, longhand idiom brackets...
_c4 <- join $ openDbConnection3 <$> readConfigData <*> readConfigData <*> readConfigData
return ()