2{-# LANGUAGE EmptyDataDecls #-}
4{-# LANGUAGE PatternGuards #-}
5{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE TemplateHaskell #-}
7{-# LANGUAGE TypeOperators #-}
8#ifdef USE_REFLEX_OPTIMIZER
9{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
11-- | Template Haskell helper functions for building complex 'Dynamic' values.
12module Reflex.Dynamic.TH
16 -- * Deprecated functions
23import Control.Monad.State
27import qualified Language.Haskell.Exts as Hs
28import qualified Language.Haskell.Meta.Syntax.Translate as Hs
29import Language.Haskell.TH
30import Language.Haskell.TH.Quote
31import qualified Language.Haskell.TH.Syntax as TH
33-- | Quote a 'Dynamic' expression. Within the quoted expression, you can use
34-- @$(unqDyn [| x |])@ to refer to any expression @x@ of type @Dynamic t a@; the
35-- unquoted result will be of type @a@
36qDynPure :: Q Exp -> Q Exp
39 let f :: forall d. Data d => d -> StateT [(Name, Exp)] Q d
41 Just (Refl :: d :~: Exp)
42 | AppE (VarE m) eInner <- d
44 -> do n <- lift $ newName "dynamicQuotedExpressionVariable"
48 (e', exprsReversed) <- runStateT (gmapM f e) []
49 let exprs = reverse exprsReversed
50 arg = foldr (\a b -> ConE 'FHCons `AppE` snd a `AppE` b) (ConE 'FHNil) exprs
51 param = foldr (\a b -> ConP 'HCons [VarP (fst a), b]) (ConP 'HNil []) exprs
52 [| $(return $ LamE [param] e') <$> distributeFHListOverDynPure $(return arg) |]
54-- | Antiquote a 'Dynamic' expression. This can /only/ be used inside of a
56unqDyn :: Q Exp -> Q Exp
57unqDyn e = [| unqMarker $e |]
59-- | This type represents an occurrence of unqDyn before it has been processed
60-- by qDyn. If you see it in a type error, it probably means that unqDyn has
61-- been used outside of a qDyn context.
64-- unqMarker must not be exported; it is used only as a way of smuggling data
67--TODO: It would be much nicer if the TH AST was extensible to support this kind of thing without trickery
68unqMarker :: a -> UnqDyn
69unqMarker = error "An unqDyn expression was used outside of a qDyn expression"
71-- | Create a 'Dynamic' value using other 'Dynamic's as inputs. The result is
72-- sometimes more concise and readable than the equivalent 'Applicative'-based
73-- expression. For example:
75-- > [mkDyn| $x + $v * $t + 1/2 * $a * $t ^ 2 |]
77-- would have a very cumbersome 'Applicative' encoding.
78mkDynPure :: QuasiQuoter
79mkDynPure = QuasiQuoter
81 , quotePat = error "mkDyn: pattern splices are not supported"
82 , quoteType = error "mkDyn: type splices are not supported"
83 , quoteDec = error "mkDyn: declaration splices are not supported"
86mkDynExp :: String -> Q Exp
87mkDynExp s = case Hs.parseExpWithMode (Hs.defaultParseMode { Hs.extensions = [ Hs.EnableExtension Hs.TemplateHaskell ] }) s of
88 Hs.ParseFailed (Hs.SrcLoc _ l c) err -> fail $ "mkDyn:" <> show l <> ":" <> show c <> ": " <> err
89 Hs.ParseOk e -> qDynPure $ return $ everywhere (id `extT` reinstateUnqDyn) $ Hs.toExp $ everywhere (id `extT` antiE) e
90 where TH.Name (TH.OccName occName) (TH.NameG _ _ (TH.ModName modName)) = 'unqMarker
91#if MIN_VERSION_haskell_src_exts(1,18,0)
92 antiE :: Hs.Exp Hs.SrcSpanInfo -> Hs.Exp Hs.SrcSpanInfo
95 Hs.App l (Hs.Var l $ Hs.Qual l (Hs.ModuleName l modName) (Hs.Ident l occName)) $ case se of
96 Hs.IdSplice l2 v -> Hs.Var l2 $ Hs.UnQual l2 $ Hs.Ident l2 v
97 Hs.ParenSplice _ ps -> ps
102 Hs.App (Hs.Var $ Hs.Qual (Hs.ModuleName modName) (Hs.Ident occName)) $ case se of
103 Hs.IdSplice v -> Hs.Var $ Hs.UnQual $ Hs.Ident v
104 Hs.ParenSplice ps -> ps
107 reinstateUnqDyn (TH.Name (TH.OccName occName') (TH.NameQ (TH.ModName modName')))
108 | modName == modName' && occName == occName' = 'unqMarker
109 reinstateUnqDyn x = x
111--------------------------------------------------------------------------------
113--------------------------------------------------------------------------------
115{-# DEPRECATED qDyn "Instead of $(qDyn x), use return $(qDynPure x)" #-}
116-- | Like 'qDynPure', but wraps its result monadically using 'return'. This is
117-- no longer necessary, due to 'Dynamic' being an instance of 'Functor'.
118qDyn :: Q Exp -> Q Exp
119qDyn qe = [| return $(qDynPure qe) |]
121{-# DEPRECATED mkDyn "Instead of [mkDyn| x |], use return [mkDynPure| x |]" #-}
122-- | Like 'mkDynPure', but wraps its result monadically using 'return'. This is
123-- no longer necessary, due to 'Dynamic' being an instance of 'Functor'.
126 { quoteExp = \s -> [| return $(mkDynExp s) |]
127 , quotePat = error "mkDyn: pattern splices are not supported"
128 , quoteType = error "mkDyn: type splices are not supported"
129 , quoteDec = error "mkDyn: declaration splices are not supported"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list