on master help sign in
Improve TH generator
commitac918fc780620173f44a302729ccf11b502c264f authorIndex Int <vlad.z.4096@gmail.com> dateSat 6 Jun 2015, 12:41 (11 years ago) parenteaa9635
2 files changed+80−37
src/Control/Ether/TH.hs+58−21 test/Regression.hs+22−16
src/Control/Ether/TH.hs+58−21
@@ -1,44 +1,81 @@
11{-# LANGUAGE TemplateHaskell #-}
22module Control.Ether.TH
3− ( etherealReader
3+ ( ethereal
4+ , EtherealConfig (..)
5+ , defaultEtherealReaderConfig
46 ) where
57
68import qualified Language.Haskell.TH as TH
79
810import Data.Proxy
11+import Data.Functor.Identity
912import Control.Ether.Core
1013import Control.Monad.Ether.Reader
1114
1215emptyDataDecl :: TH.Name -> TH.DecQ
1316emptyDataDecl name = TH.dataD (return []) name [] [] []
1417
15−etherealReader :: String -> String -> String -> TH.Name -> TH.DecsQ
16−etherealReader strTagName strRunName strAskName tyname = do
17− let tagName = TH.mkName strTagName
18+funSimple :: TH.Name -> TH.ExpQ -> TH.DecQ
19+funSimple name body = TH.funD name [ TH.clause [] (TH.normalB body) [] ]
20+
21+tyVar :: String -> TH.Q (TH.TyVarBndr, TH.TypeQ)
22+tyVar name = do
23+ thName <- TH.newName name
24+ let thType = TH.varT thName
25+ return (TH.PlainTV thName, thType)
26+
27+data EtherealConfig
28+ = EtherealReaderConfig TH.Name String String String String String
29+
30+defaultEtherealReaderConfig :: TH.Name -> String -> EtherealConfig
31+defaultEtherealReaderConfig tyname name = EtherealReaderConfig
32+ tyname
33+ ("Monad" ++ name)
34+ ("Tag" ++ name)
35+ ("run" ++ name ++ "T")
36+ ("run" ++ name)
37+ ("ask" ++ name)
38+
39+ethereal :: EtherealConfig -> TH.DecsQ
40+
41+ethereal (EtherealReaderConfig
42+ tyname strEffName
43+ strTagName strRunTransName
44+ strRunName strAskName) = do
45+ let effName = TH.mkName strEffName
46+ tagName = TH.mkName strTagName
1847 tag = TH.conT tagName
48+ runTransName = TH.mkName strRunTransName
1949 runName = TH.mkName strRunName
2050 askName = TH.mkName strAskName
51+ effDecl <- TH.tySynD effName [] [t| MonadEtherReader $tag |]
2152 tagDecl <- emptyDataDecl tagName
2253 [tagInst] <- [d| type instance EtherData $tag = $(TH.conT tyname) |]
54+ runTransFunSig <- do
55+ (mBndr, m) <- tyVar "m"
56+ (aBndr, a) <- tyVar "a"
57+ TH.sigD runTransName
58+ $ TH.forallT [mBndr, aBndr] (return [])
59+ [t| EtherReaderT $tag $m $a -> EtherData $tag -> $m $a |]
60+ runTransFunBody <- funSimple runTransName
61+ [e| runEtherReaderT (Proxy :: Proxy $tag) |]
2362 runFunSig <- do
24− mName <- TH.newName "m"
25− aName <- TH.newName "a"
26− let m' = TH.varT mName
27− a' = TH.varT aName
28− ty = TH.forallT [TH.PlainTV mName, TH.PlainTV aName] (return [])
29− [t| EtherReaderT $tag $m' $a' -> EtherData $tag -> $m' $a' |]
30− TH.sigD runName ty
31− runFunBody <-
32− let body = [e| runEtherReaderT (Proxy :: Proxy $tag) |]
33− in TH.funD runName [ TH.clause [] (TH.normalB body) [] ]
63+ (aBndr, a) <- tyVar "a"
64+ TH.sigD runName
65+ $ TH.forallT [aBndr] (return [])
66+ [t| EtherReaderT $tag Identity $a -> EtherData $tag -> $a |]
67+ runFunBody <- funSimple runName
68+ [e| ((runIdentity.).) $(TH.varE runTransName) |]
3469 askFunSig <- do
35− mName <- TH.newName "m"
36− let m' = TH.varT mName
37− ty = TH.forallT [TH.PlainTV mName]
38− (sequence [ [t| MonadEtherReader $tag $m' |] ])
39− [t| $m' (EtherData $tag) |]
40− TH.sigD askName ty
70+ (mBndr, m) <- tyVar "m"
71+ TH.sigD askName
72+ $ TH.forallT [mBndr]
73+ (sequence [ [t| MonadEtherReader $tag $m |] ])
74+ [t| $m (EtherData $tag) |]
4175 askFunBody <-
4276 let body = [e| etherAsk (Proxy :: Proxy $tag) |]
4377 in TH.funD askName [ TH.clause [] (TH.normalB body) [] ]
44− return [ tagDecl, tagInst, runFunSig, runFunBody, askFunSig, askFunBody ]
78+ return [ effDecl, tagDecl, tagInst
79+ , runTransFunSig, runTransFunBody
80+ , runFunSig, runFunBody
81+ , askFunSig, askFunBody ]
test/Regression.hs+22−16
@@ -9,17 +9,13 @@ import Control.Ether.TH
99import Control.Monad.Ether.Reader
1010
1111import Data.Proxy
12−import Data.Functor.Identity
1312
1413import Test.Tasty
1514import Test.Tasty.QuickCheck
1615import Test.QuickCheck.Function
1716
18−etherealReader "AmountTag" "runAmountT" "askAmount" ''Int
19−type MonadAmount = MonadEtherReader AmountTag
20−
21−etherealReader "CountTag" "runCountT" "askCount" ''Integer
22−type MonadCount = MonadEtherReader CountTag
17+ethereal (defaultEtherealReaderConfig ''Int "Amount")
18+ethereal (defaultEtherealReaderConfig ''Integer "Count")
2319
2420main :: IO ()
2521main = defaultMain suite
@@ -33,28 +29,38 @@ suite = testGroup "Ether"
3329 ]
3430
3531layeredLocalLeft, layeredLocalRight
36− :: Fun (Int, Integer) Integer -> Fun Integer Integer -> Int -> Integer -> Property
32+ :: Fun (Int, Integer) Integer
33+ -> Fun Integer Integer
34+ -> Int -> Integer -> Property
3735
38−layeredLocalLeft k f a1 a2 = property (direct == indirect)
36+layeredLocalLeft k f a1 a2 = property (direct == run indirect)
3937 where
40− run = runIdentity . flip runAmountT a1 . flip runCountT a2
41− direct = apply k (fromIntegral a1, apply f a2)
42− indirect = run $ layeredLocalCore (apply f) (\n m -> apply k (fromIntegral n, m))
38+ run = flip runAmount a1 . flip runCountT a2
39+ (direct, indirect) = layeredLocalCore' k f a1 a2
4340
44−layeredLocalRight k f a1 a2 = property (direct == indirect)
41+layeredLocalRight k f a1 a2 = property (direct == run indirect)
4542 where
46− run = runIdentity . flip runCountT a2 . flip runAmountT a1
47− direct = apply k (fromIntegral a1, apply f a2)
48− indirect = run $ layeredLocalCore (apply f) (\n m -> apply k (fromIntegral n, m))
43+ run = flip runCount a2 . flip runAmountT a1
44+ (direct, indirect) = layeredLocalCore' k f a1 a2
4945
5046layeredLocalCore
5147 :: (MonadAmount m, MonadCount m)
5248 => (Integer -> Integer) -> (Int -> Integer -> a) -> m a
5349layeredLocalCore f g = do
5450 n <- askAmount
55− m <- etherLocal (Proxy :: Proxy CountTag) f askCount
51+ m <- etherLocal (Proxy :: Proxy TagCount) f askCount
5652 return (g n m)
5753
54+layeredLocalCore'
55+ :: (MonadAmount m, MonadCount m)
56+ => Fun (Int, Integer) Integer
57+ -> Fun Integer Integer
58+ -> Int -> Integer -> (Integer, m Integer)
59+layeredLocalCore' k f a1 a2 = (direct, indirect)
60+ where
61+ direct = apply k (fromIntegral a1, apply f a2)
62+ indirect = layeredLocalCore (apply f) (\n m -> apply k (fromIntegral n, m))
63+
5864-- this should not compile
5965z :: IO Int
6066z = runAmountT (runAmountT (runAmountT askAmount 20) 10) 5