-- Exponential with GHC 8.10 {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module T13253 where import Control.Monad (liftM) import Control.Monad.Trans.RWS.Lazy -- check how strict behaves import Control.Monad.Trans.Reader (ReaderT) import Control.Monad.IO.Class (MonadIO (..)) import Control.Monad.Trans.Class (MonadTrans (..)) import Data.ByteString (ByteString) import Data.Monoid (Any (..)) import Data.Semigroup (Semigroup (..)) import Data.String (IsString (..)) import System.Environment (getEnv) type Handler = ReaderT () IO type MForm = RWST (Maybe ([(String, Text)], ()), (), ()) Any [Int] type Text = ByteString -- close enough data HugeStruct = HugeStruct !Text !Text !Text !Text !Text !Text !Text !Text !Text -- 9th !Text !Text data FormResult a = FormMissing | FormFailure [Text] | FormSuccess a deriving Show instance Functor FormResult where fmap _ FormMissing = FormMissing fmap _ (FormFailure errs) = FormFailure errs fmap f (FormSuccess a) = FormSuccess $ f a instance Applicative FormResult where pure = FormSuccess (FormSuccess f) <*> (FormSuccess g) = FormSuccess $ f g (FormFailure x) <*> (FormFailure y) = FormFailure $ x ++ y (FormFailure x) <*> _ = FormFailure x _ <*> (FormFailure y) = FormFailure y _ <*> _ = FormMissing instance Monoid m => Monoid (FormResult m) where mempty = pure mempty mappend = (<>) instance Semigroup m => Semigroup (FormResult m) where x <> y = (<>) <$> x <*> y mreq :: MonadIO m => String -> MForm m (FormResult Text, ()) -- fast --mreq v = pure (FormFailure [], ()) -- slow mreq v = mhelper v (\m l -> FormFailure ["fail"]) FormSuccess askParams :: Monad m => MForm m (Maybe [(String, Text)]) askParams = do (x, _, _) <- ask return $ liftM fst x mhelper :: MonadIO m => String -> (() -> () -> FormResult b) -- on missing -> (Text -> FormResult b) -- on success -> MForm m (FormResult b, ()) mhelper v onMissing onFound = do -- without tell, also faster tell (Any True) -- with different "askParams": faster. -- mp <- liftIO $ read <$> readFile v mp <- askParams (res, x) <- case mp of Nothing -> return (FormMissing, ()) Just p -> do return $ case lookup v p of Nothing -> (onMissing () (), ()) Just t -> (onFound t, ()) return (res, x) -- not inlining, also faster: -- {-# NOINLINE mhelper #-} sampleForm2 :: MForm Handler (FormResult HugeStruct) sampleForm2 = do (x01, _) <- mreq "UNUSED" (x02, _) <- mreq "UNUSED" (x03, _) <- mreq "UNUSED" (x04, _) <- mreq "UNUSED" (x05, _) <- mreq "UNUSED" (x06, _) <- mreq "UNUSED" (x07, _) <- mreq "UNUSED" (x08, _) <- mreq "UNUSED" (x09, _) <- mreq "UNUSED" (x10, _) <- mreq "UNUSED" (x11, _) <- mreq "UNUSED" let hugeStructRes = HugeStruct <$> x01 <*> x02 <*> x03 <*> x04 <*> x05 <*> x06 <*> x07 <*> x08 <*> x09 <*> x10 <*> x11 pure hugeStructRes main :: IO () main = pure ()