on master help sign in
QuasiQuoter for tags
commit731282345678c8f7b1015aab65141325f403cbd7 authorIndex Int <vlad.z.4096@gmail.com> dateSat 30 Apr 2016, 15:08 (10 years ago) parent5c5f6d5
10 files changed+61−88
ether.cabal+2 src/Control/Ether/TH.hs+9−36 src/Control/Monad/Ether.hs+1−1 src/Control/Monad/Ether/Implicit.hs−1 test/Regression/T1.hs+9−9 test/Regression/T3.hs+13−13 test/Regression/T4.hs+4−4 test/Regression/T7.hs+4−4 test/Regression/T8.hs+10−10 test/Regression/T9.hs+9−10
ether.cabal+2
@@ -98,6 +98,7 @@ test-suite regression
9898 , tasty >=0.10
9999 , tasty-quickcheck >=0.8
100100 , QuickCheck >=2.8
101+ , ghc-prim >=0.3
101102 , ether
102103
103104 main-is: Regression.hs
@@ -126,4 +127,5 @@ test-suite regression
126127 TemplateHaskell
127128 TypeFamilies
128129 TypeOperators
130+ QuasiQuotes
129131 ghc-options: -Wall -fno-warn-missing-signatures
src/Control/Ether/TH.hs+9−36
@@ -1,46 +1,19 @@
11{-# LANGUAGE TemplateHaskell #-}
22{-# LANGUAGE MagicHash #-}
3−{-# LANGUAGE CPP #-}
43
54-- | Template Haskell utilities.
65
7−module Control.Ether.TH
8− ( ethereal
9− ) where
6+module Control.Ether.TH (tag) where
107
118import qualified Language.Haskell.TH as TH
9+import qualified Language.Haskell.TH.Quote as TH
1210
1311import GHC.Prim (Proxy#, proxy#)
1412
15−emptyDataDecl :: TH.Name -> TH.DecQ
16−#if __GLASGOW_HASKELL__ < 800
17−emptyDataDecl name = TH.dataD (return []) name [] [] []
18−#else
19−emptyDataDecl name = TH.dataD (return []) name [] Nothing [] (return [])
20−#endif
21−
22−funSimple :: TH.Name -> TH.ExpQ -> TH.DecQ
23−funSimple name body = TH.funD name [ TH.clause [] (TH.normalB body) [] ]
24−
25−proxySimple :: TH.Name -> TH.TypeQ -> TH.Q (TH.Dec, TH.Dec)
26−proxySimple name ty = do
27− sig <- TH.sigD name [t| Proxy# $ty |]
28− val <- funSimple name [e| proxy# |]
29− return (sig, val)
30−
31−-- |
32−-- Creates a tag and a value-level proxy for it.
33−--
34−-- @'ethereal' \"Foo\" \"foo\"@ generates the following code:
35−--
36−-- > data Foo
37−-- > foo :: Proxy Foo
38−-- > foo = Proxy
39−ethereal :: String -> String -> TH.DecsQ
40−ethereal strTagName strTagProxyName = do
41− let tagName = TH.mkName strTagName
42− tag = TH.conT tagName
43− tagProxyName = TH.mkName strTagProxyName
44− tagDecl <- emptyDataDecl tagName
45− (tagProxySig, tagProxyVal) <- proxySimple tagProxyName tag
46− return [tagDecl, tagProxySig, tagProxyVal]
13+tag :: TH.QuasiQuoter
14+tag = TH.QuasiQuoter proxyExpQ undefined undefined undefined
15+ where
16+ proxyExpQ :: String -> TH.ExpQ
17+ proxyExpQ nameStr =
18+ let ty = TH.conT (TH.mkName nameStr)
19+ in [e| proxy# :: Proxy# $ty |]
src/Control/Monad/Ether.hs+1−1
@@ -11,4 +11,4 @@ import Control.Monad.Ether.Writer as X
1111import Control.Monad.Ether.State as X
1212import Control.Monad.Ether.Except as X
1313import Control.Monad.Trans.Ether.Dispatch as X
14−import Control.Ether.TH as X (ethereal)
14+import Control.Ether.TH as X (tag)
src/Control/Monad/Ether/Implicit.hs−1
@@ -11,4 +11,3 @@ import Control.Monad.Ether.Implicit.Writer as X
1111import Control.Monad.Ether.Implicit.State as X
1212import Control.Monad.Ether.Implicit.Except as X
1313import Control.Monad.Trans.Ether.Dispatch as X
14−import Control.Ether.TH as X (ethereal)
test/Regression/T1.hs+9−9
@@ -6,24 +6,24 @@ import Control.Ether.Abbr
66import Test.Tasty
77import Test.Tasty.QuickCheck
88
9−ethereal "Tag1" "tag1"
10−ethereal "Tag2" "tag2"
9+data Tag1
10+data Tag2
1111
1212testEther
1313 :: Ether '[Tag1 --> String, Tag2 --> String] m
1414 => m ((String, String), (String, String))
1515testEther = do
16− s1 <- ask tag1
17− s2 <- ask tag2
16+ s1 <- ask [tag|Tag1|]
17+ s2 <- ask [tag|Tag2|]
1818 let s1s2 = (s1, s2)
19− s1s2' <- local tag2 (map succ) $ do
20− s1' <- ask tag1
21− s2' <- ask tag2
19+ s1s2' <- local [tag|Tag2|] (map succ) $ do
20+ s1' <- ask [tag|Tag1|]
21+ s2' <- ask [tag|Tag2|]
2222 return (s1', s2')
2323 return (s1s2, s1s2')
2424
25−runner1 s1 s2 = flip (runReader tag1) s1 . flip (runReaderT tag2) s2
26−runner2 s1 s2 = flip (runReader tag2) s2 . flip (runReaderT tag1) s1
25+runner1 s1 s2 = flip (runReader [tag|Tag1|]) s1 . flip (runReaderT [tag|Tag2|]) s2
26+runner2 s1 s2 = flip (runReader [tag|Tag2|]) s2 . flip (runReaderT [tag|Tag1|]) s1
2727
2828test1 :: TestTree
2929test1 = testGroup "T1: Reader local environment"
test/Regression/T3.hs+13−13
@@ -9,8 +9,8 @@ import qualified Control.Monad.State as T
99import Test.Tasty
1010import Test.Tasty.QuickCheck
1111
12−ethereal "RTag" "rTag"
13−ethereal "STag" "sTag"
12+data RTag
13+data STag
1414
1515testMTL :: (T.MonadReader Int m, T.MonadState Int m) => m Int
1616testMTL = do
@@ -22,21 +22,21 @@ testMTL = do
2222testEther
2323 :: Ether '[STag --> Int, STag <-> Int, RTag --> Int] m
2424 => m (Int, Int, Int)
25−testEther = local rTag (*2) $ do
26− a_mul_b <- tagAttach sTag testMTL
27− a_add_b <- get sTag
28− modify sTag negate
29− c <- ask rTag
25+testEther = local [tag|RTag|] (*2) $ do
26+ a_mul_b <- tagAttach [tag|STag|] testMTL
27+ a_add_b <- get [tag|STag|]
28+ modify [tag|STag|] negate
29+ c <- ask [tag|RTag|]
3030 return (a_mul_b, a_add_b, c)
3131
3232runner1 s r
33− = flip (runReader rTag) (negate r)
34− . flip (runReaderT sTag) r
35− . flip (runStateT sTag) s
33+ = flip (runReader [tag|RTag|]) (negate r)
34+ . flip (runReaderT [tag|STag|]) r
35+ . flip (runStateT [tag|STag|]) s
3636runner2 s r
37− = flip (runReader rTag) (negate r)
38− . flip (runStateT sTag) s
39− . flip (runReaderT sTag) r
37+ = flip (runReader [tag|RTag|]) (negate r)
38+ . flip (runStateT [tag|STag|]) s
39+ . flip (runReaderT [tag|STag|]) r
4040
4141test3 :: TestTree
4242test3 = testGroup "T3: Tag attachement"
test/Regression/T4.hs+4−4
@@ -6,14 +6,14 @@ import Control.Monad.Ether
66import Test.Tasty
77import Test.Tasty.QuickCheck
88
9−ethereal "RTag" "rTag"
9+data RTag
1010
1111testEther :: Ether '[RTag --> Int] m => m Int
12−testEther = ask rTag
12+testEther = ask [tag|RTag|]
1313
1414runner r
15− = flip (runReader rTag) (r' :: Int)
16− . flip (runReaderT rTag) (r :: Int)
15+ = flip (runReader [tag|RTag|]) (r' :: Int)
16+ . flip (runReaderT [tag|RTag|]) (r :: Int)
1717 where
1818 r' = negate r
1919
test/Regression/T7.hs+4−4
@@ -9,7 +9,7 @@ import qualified Control.Monad.Writer as T
99import Test.Tasty
1010import Test.Tasty.QuickCheck
1111
12−ethereal "WTag" "wTag"
12+data WTag
1313
1414testEther
1515 :: Num a
@@ -19,16 +19,16 @@ testEther
1919testEther xs = do
2020 forM_ xs $ \x -> do
2121 T.tell (Sum x)
22− tell wTag (Sum 1)
22+ tell [tag|WTag|] (Sum 1)
2323
2424runner1 :: Num a => [a] -> (a, a)
2525runner1 xs =
26− let (s, c) = T.runWriter . execWriterT wTag $ testEther xs
26+ let (s, c) = T.runWriter . execWriterT [tag|WTag|] $ testEther xs
2727 in (getSum s, getSum c)
2828
2929runner2 :: Num a => [a] -> (a, a)
3030runner2 xs =
31− let (c, s) = runWriter wTag . T.execWriterT $ testEther xs
31+ let (c, s) = runWriter [tag|WTag|] . T.execWriterT $ testEther xs
3232 in (getSum s, getSum c)
3333
3434triangular :: Integral a => a -> a
test/Regression/T8.hs+10−10
@@ -8,8 +8,8 @@ import qualified Control.Monad.State as T
88import Test.Tasty
99import Test.Tasty.QuickCheck
1010
11−ethereal "Foo" "foo"
12−ethereal "Bar" "bar"
11+data Foo
12+data Bar
1313
1414testMTL1 :: T.MonadState Int m => m ()
1515testMTL1 = T.modify negate
@@ -21,22 +21,22 @@ testEther
2121 :: Ether '[Foo <-> Int, Bar <-> Bool] m
2222 => m String
2323testEther = do
24− tagAttach foo testMTL1
25− tagAttach bar testMTL2
26− a <- gets foo show
27− b <- gets bar show
24+ tagAttach [tag|Foo|] testMTL1
25+ tagAttach [tag|Bar|] testMTL2
26+ a <- gets [tag|Foo|] show
27+ b <- gets [tag|Bar|] show
2828 return (a ++ b)
2929
3030model :: Int -> Bool -> String
3131model a b = show (negate a) ++ show (not b)
3232
3333runner1 a b
34− = flip (evalState foo) a
35− . flip (evalStateT bar) b
34+ = flip (evalState [tag|Foo|]) a
35+ . flip (evalStateT [tag|Bar|]) b
3636
3737runner2 a b
38− = flip (evalState bar) b
39− . flip (evalStateT foo) a
38+ = flip (evalState [tag|Bar|]) b
39+ . flip (evalStateT [tag|Foo|]) a
4040
4141test8 :: TestTree
4242test8 = testGroup "T8: Multiple tag attachements"
test/Regression/T9.hs+9−10
@@ -6,17 +6,16 @@ import Control.Monad.Ether
66import Test.Tasty
77import Test.Tasty.QuickCheck
88
9−ethereal "Foo" "foo"
10−ethereal "Bar" "bar"
11−
9+data Foo
10+data Bar
1211
1312testEther1 :: Ether '[Foo <-> Int] m => m String
1413testEther1 = do
15− modify foo negate
16− gets foo show
14+ modify [tag|Foo|] negate
15+ gets [tag|Foo|] show
1716
1817testEther2 :: Ether '[Bar <-> Int] m => m String
19−testEther2 = tagReplace foo bar testEther1
18+testEther2 = tagReplace [tag|Foo|] [tag|Bar|] testEther1
2019
2120testEther
2221 :: Ether '[Foo <-> Int, Bar <-> Int] m
@@ -30,12 +29,12 @@ model :: Int -> Int -> String
3029model a b = show (negate a) ++ show (negate b)
3130
3231runner1 a b
33− = flip (evalState foo) a
34− . flip (evalStateT bar) b
32+ = flip (evalState [tag|Foo|]) a
33+ . flip (evalStateT [tag|Bar|]) b
3534
3635runner2 a b
37− = flip (evalState bar) b
38− . flip (evalStateT foo) a
36+ = flip (evalState [tag|Bar|]) b
37+ . flip (evalStateT [tag|Foo|]) a
3938
4039test9 :: TestTree
4140test9 = testGroup "T9: Tag replacement"