Skip to content

Commit d48a95a

Browse files
LibbyLibby
authored andcommitted
Use plain Haskell functions instead of StateT
1 parent 1c2c328 commit d48a95a

6 files changed

Lines changed: 73 additions & 56 deletions

File tree

src/Web/Larceny.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ renderWith l sub s = renderRelative l sub s []
130130
renderRelative :: Library s -> Substitutions s -> s -> Path -> Path -> IO (Maybe Text)
131131
renderRelative l sub s givenPath targetPath =
132132
case findTemplate l givenPath targetPath of
133-
(pth, Just (Template run)) -> Just <$> evalStateT (run pth sub l) s
133+
(pth, Just (Template run)) -> Just <$> fst <$> run pth sub l s
134134
(_, Nothing) -> return Nothing
135135

136136
-- | Load all the templates in some directory into a Library.

src/Web/Larceny/Fills.hs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ module Web.Larceny.Fills ( textFill
1717
, (%)) where
1818

1919
import Control.Exception
20-
import Control.Monad.State (StateT)
20+
import Control.Monad (foldM)
21+
import Control.Monad.State (StateT, runStateT)
2122
import qualified Data.Map as M
2223
import Data.Maybe (fromMaybe)
2324
import Data.Text (Text)
@@ -100,7 +101,9 @@ rawTextFill t = rawTextFill' (return t)
100101
-- textFill' getTextFromDatabase
101102
-- @
102103
textFill' :: StateT s IO Text -> Fill s
103-
textFill' t = Fill $ \_m _t _l -> HE.text <$> t
104+
textFill' t = Fill $ \_m _t _l st -> do
105+
(t, st') <- runStateT t st
106+
return (HE.text t, st')
104107

105108
-- | Use state or IO, then fill in some text.
106109
--
@@ -109,7 +112,7 @@ textFill' t = Fill $ \_m _t _l -> HE.text <$> t
109112
-- textFill' getTextFromDatabase
110113
-- @
111114
rawTextFill' :: StateT s IO Text -> Fill s
112-
rawTextFill' t = Fill $ \_m _t _l -> t
115+
rawTextFill' t = Fill $ \_m _t _l -> runStateT t
113116

114117
-- | Create substitutions for each element in a list and fill the child nodes
115118
-- with those substitutions.
@@ -124,17 +127,26 @@ rawTextFill' t = Fill $ \_m _t _l -> t
124127
mapSubs :: (a -> Substitutions s)
125128
-> [a]
126129
-> Fill s
127-
mapSubs f xs = Fill $ \_attrs (pth, tpl) lib ->
128-
T.concat <$> mapM (\n -> runTemplate tpl pth (f n) lib) xs
130+
mapSubs f xs = Fill $ \_attrs (pth, tpl) lib st ->
131+
foldM
132+
(\(text, st) item -> do
133+
(t , st') <- runTemplate tpl pth (f item) lib st
134+
return (text <> t, st'))
135+
("", st)
136+
xs
129137

130138
-- | Create substitutions for each element in a list (using IO/state if
131139
-- needed) and fill the child nodes with those substitutions.
132140
mapSubs' :: (a -> StateT s IO (Substitutions s)) -> [a] -> Fill s
133141
mapSubs' f xs = Fill $
134-
\_m (pth, tpl) lib ->
135-
T.concat <$> mapM (\x -> do
136-
s' <- f x
137-
runTemplate tpl pth s' lib) xs
142+
\_m (pth, tpl) lib st ->
143+
foldM
144+
(\(text, st) item -> do
145+
(s', st' ) <- runStateT (f item) st
146+
(t , st'') <- runTemplate tpl pth s' lib st'
147+
return (text <> t, st''))
148+
("", st)
149+
xs
138150

139151
-- | Fill in the child nodes of the blank with substitutions already
140152
-- available.
@@ -198,11 +210,11 @@ maybeFillChildrenWith (Just s) = Fill $ \_s (pth, Template tpl) l ->
198210
--
199211
-- > Bonnie Thunders
200212
maybeFillChildrenWith' :: StateT s IO (Maybe (Substitutions s)) -> Fill s
201-
maybeFillChildrenWith' sMSubs = Fill $ \_s (pth, Template tpl) l -> do
202-
mSubs <- sMSubs
213+
maybeFillChildrenWith' sMSubs = Fill $ \_s (pth, Template tpl) l st -> do
214+
(mSubs, newState) <- runStateT sMSubs st
203215
case mSubs of
204-
Nothing -> return ""
205-
Just s -> tpl pth s l
216+
Nothing -> return ("", newState)
217+
Just s -> tpl pth s l newState
206218

207219
-- | Use attributes from the the blank as arguments to the fill.
208220
--

src/Web/Larceny/Internal.hs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -96,22 +96,23 @@ toLarcenyNode _ (X.NodeInstruction _) = NodeContent ""
9696
mk :: Overrides -> [Node] -> Template s
9797
mk o = f
9898
where f nodes =
99-
Template $ \pth m l ->
99+
Template $ \pth m l st ->
100100
let pc = ProcessContext pth m l o f nodes in
101-
do s <- get
102-
T.concat <$> toUserState (pc s) (process nodes)
101+
do (textList, st') <- toUserState (pc st) (process nodes)
102+
return (T.concat textList, st')
103103

104-
toProcessState :: StateT s IO a -> StateT (ProcessContext s) IO a
104+
105+
toProcessState :: (s -> IO (a, s)) -> StateT (ProcessContext s) IO a
105106
toProcessState f =
106107
do pc <- get
107-
(result, s') <- liftIO $ runStateT f (_pcState pc)
108+
(result, s') <- liftIO $ f (_pcState pc)
108109
pcState .= s'
109110
return result
110111

111-
toUserState :: ProcessContext s -> StateT (ProcessContext s) IO a -> StateT s IO a
112-
toUserState pc f =
113-
do s <- get
114-
liftIO $ evalStateT f (pc { _pcState = s })
112+
toUserState :: ProcessContext s -> StateT (ProcessContext s) IO a -> IO (a, s)
113+
toUserState pc f =
114+
do (a, st) <- runStateT f pc
115+
return (a, _pcState st)
115116

116117
fillIn :: Blank -> Substitutions s -> Fill s
117118
fillIn tn m = fromMaybe (fallbackFill tn m) (M.lookup tn m)
@@ -120,9 +121,9 @@ fallbackFill :: Blank -> Substitutions s -> Fill s
120121
fallbackFill FallbackBlank m = fromMaybe (textFill "") (M.lookup FallbackBlank m)
121122
fallbackFill (Blank tn) m =
122123
let fallback = fromMaybe (textFill "") (M.lookup FallbackBlank m) in
123-
Fill $ \attr (pth, tpl) lib ->
124-
do liftIO $ putStrLn ("Larceny: Missing fill for blank " <> show tn <> " in template " <> show pth)
125-
unFill fallback attr (pth, tpl) lib
124+
Fill $ \attr (pth, tpl) lib st ->
125+
do putStrLn ("Larceny: Missing fill for blank " <> show tn <> " in template " <> show pth)
126+
unFill fallback attr (pth, tpl) lib st
126127

127128
data ProcessContext s = ProcessContext { _pcPath :: Path
128129
, _pcSubs :: Substitutions s
@@ -227,11 +228,11 @@ fillAttrs attrs = M.fromList <$> mapM fill (M.toList attrs)
227228

228229
fillAttr :: Either Text Blank -> StateT (ProcessContext s) IO Text
229230
fillAttr eBlankText =
230-
do (ProcessContext pth m l _ mko _ _) <- get
231+
do pc@(ProcessContext pth m l _ mko _ _) <- get
231232
toProcessState $
232233
case eBlankText of
233234
Right hole -> unFill (fillIn hole m) mempty (pth, mko []) l
234-
Left text -> return text
235+
Left text -> \s -> return (text, s)
235236

236237
-- Look up the Fill for the hole. Apply the Fill to a map of
237238
-- attributes, a Template made from the child nodes (adding in the

src/Web/Larceny/Types.hs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ instance Hashable Blank where
4343
hashWithSalt s (Blank tn) = s + hash tn
4444
hashWithSalt s FallbackBlank = s + hash ("FallbackBlank" :: Text)
4545

46+
-- A transitional type
47+
type StateTsIOText s = IO (Text, s)
48+
4649
-- | A Fill is how to fill in a Blank.
4750
--
4851
-- In most cases, you can use helper functions like `textFill` or
@@ -69,7 +72,8 @@ instance Hashable Blank where
6972
newtype Fill s = Fill { unFill :: Attributes
7073
-> (Path, Template s)
7174
-> Library s
72-
-> StateT s IO Text }
75+
-> s
76+
-> StateTsIOText s }
7377

7478
-- | The Blank's attributes, a map from the attribute name to
7579
-- it's value.
@@ -118,7 +122,8 @@ fallbackSub fill = M.fromList [(FallbackBlank, fill)]
118122
newtype Template s = Template { runTemplate :: Path
119123
-> Substitutions s
120124
-> Library s
121-
-> StateT s IO Text }
125+
-> s
126+
-> StateTsIOText s }
122127

123128
-- | The path to a template.
124129
type Path = [Text]

test/Examples.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ subst = subs [ ("site-title", textFill "Gotham Girls roster")
6464

6565
modifyInnerText :: (Text -> Text) -> Fill ()
6666
modifyInnerText f = Fill $
67-
\_attrs (_pth, tpl) _l ->
67+
\_attrs (_pth, tpl) _l st ->
6868
liftIO $ do
69-
t' <- evalStateT (runTemplate tpl ["default"] mempty mempty) ()
70-
return $ f t'
69+
(t', st') <- runTemplate tpl ["default"] mempty mempty st
70+
return $ (f t', st')
7171

7272
tplLib :: Library ()
7373
tplLib = M.fromList [(["skater"], parse "Beyonslay")]

test/Spec.hs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ renderM :: Text -> LarcenyHspecM Text
116116
renderM templateText = do
117117
(LarcenyHspecState _ (LarcenyState p s l o)) <- S.get
118118
let tpl = parseWithOverrides o (LT.fromStrict templateText)
119-
liftIO $ evalStateT (runTemplate tpl p s l) ()
119+
(a, s) <- liftIO $ runTemplate tpl p s l ()
120+
return a
120121

121122
shouldRenderM :: Text -> Text -> LarcenyHspecM ()
122123
shouldRenderM templateText output = do
@@ -325,19 +326,19 @@ spec = hspec $ do
325326
it "should allow you to write functions for fills" $ do
326327
let subs' =
327328
subs [("desc",
328-
Fill $ \m _t _l -> return $ T.take (read $ T.unpack (m M.! "length"))
329-
"A really long description"
330-
<> "...")]
329+
Fill $ \m _t _l s -> return (T.take (read $ T.unpack (m M.! "length"))
330+
"A really long description"
331+
<> "...", s))]
331332
hLarcenyState.lSubs .= subs'
332333
"<l:desc length=\"10\" />" `shouldRenderM` "A really l..."
333334

334335
it "should allow you to use IO in fills" $ do
335336
let subs' =
336337
subs [("desc", Fill $
337-
\m _t _l -> do liftIO $ putStrLn "***********\nHello World\n***********"
338-
return $ T.take (read $ T.unpack (m M.! "length"))
339-
"A really long description"
340-
<> "...")]
338+
\m _t _l s -> do putStrLn "***********\nHello World\n***********"
339+
return (T.take (read $ T.unpack (m M.! "length"))
340+
"A really long description"
341+
<> "...", s))]
341342
hLarcenyState.lSubs .= subs'
342343
"<l:desc length=\"10\" />" `shouldRenderM` "A really l..."
343344

@@ -383,7 +384,7 @@ spec = hspec $ do
383384
`shouldRenderM` "<p class=\"lots of space\"></p>"
384385

385386
it "should know what the template path is" $ do
386-
let fill = Fill $ \_ (p, _) _ -> return (head p)
387+
let fill = Fill $ \_ (p, _) _ s -> return (head p, s)
387388
hLarcenyState.lSubs .= subs [("template", fill)]
388389
"<p class=\"${template}\"></p>"
389390
`shouldRenderM` "<p class=\"default\"></p>"
@@ -453,10 +454,9 @@ statefulTests =
453454
describe "statefulness" $ do
454455
it "a fill should be able to affect subsequent fills" $ do
455456
renderWith (M.fromList [(["default"], parse "<x/><x/>")])
456-
(subs [("x", Fill $ \_ _ _ ->
457-
do modify ((+1) :: Int -> Int)
458-
s <- get
459-
return (T.pack (show s)))])
457+
(subs [("x", Fill $ \_ _ _ s ->
458+
do let s' = s + 1
459+
return (T.pack (show s'), s'))])
460460
0
461461
["default"]
462462
`shouldReturn` Just "12"
@@ -471,10 +471,9 @@ statefulTests =
471471
\<bind tag=\"test2\">test2</bind>\
472472
\<x/><x/>"
473473
renderWith (M.fromList [(["default"], parse tpl)])
474-
(subs [("x", Fill $ \_ _ _ ->
475-
do modify ((+1) :: Int -> Int)
476-
s <- get
477-
return (T.pack (show s)))])
474+
(subs [("x", Fill $ \_ _ _ s ->
475+
do let s' = s + 1
476+
return (T.pack (show s'), s'))])
478477
0
479478
["default"]
480479
`shouldReturn` Just "12"
@@ -641,9 +640,9 @@ attrTests =
641640
it "should allow you use child elements" $ do
642641
let descTplFill =
643642
useAttrs (a"length")
644-
(\n -> Fill $ \_attrs (_pth, tpl) _l -> liftIO $ do
645-
t' <- evalStateT (runTemplate tpl ["default"] mempty mempty) ()
646-
return $ T.take n t' <> "...")
643+
(\n -> Fill $ \_attrs (_pth, tpl) _l st -> liftIO $ do
644+
(t', st') <- runTemplate tpl ["default"] mempty mempty st
645+
return (T.take n t' <> "...", st'))
647646
hLarcenyState.lSubs .= subs [ ("adverb", textFill "really")
648647
, ("desc", descTplFill)]
649648
"<l:desc length=\"10\">A <adverb /> long description</desc>"
@@ -681,8 +680,8 @@ attrTests =
681680
descFunc :: Int -> Maybe Text -> Fill ()
682681
descFunc n e = Fill $
683682
do let ending = fromMaybe "..." e
684-
\_attrs (_pth, tpl) _l -> liftIO $ do
685-
renderedText <- evalStateT (runTemplate tpl ["default"] mempty mempty) ()
686-
return $ T.take n renderedText <> ending
683+
\_attrs (_pth, tpl) _l st -> liftIO $ do
684+
(renderedText, st') <- runTemplate tpl ["default"] mempty mempty st
685+
return (T.take n renderedText <> ending, st')
687686

688687
{-# ANN module ("HLint: ignore Redundant do" :: String) #-}

0 commit comments

Comments
 (0)