1{-# LANGUAGE EmptyDataDecls #-}
3{-# LANGUAGE PatternGuards #-}
4{-# LANGUAGE ScopedTypeVariables #-}
5{-# LANGUAGE TemplateHaskell #-}
6{-# LANGUAGE TypeOperators #-}
7-- | Template Haskell helper functions for building complex 'Dynamic' values.
8module Reflex.Dynamic.TH (qDyn, unqDyn, mkDyn) where
12import Control.Monad.State
16import qualified Language.Haskell.Exts as Hs
17import qualified Language.Haskell.Meta.Syntax.Translate as Hs
18import Language.Haskell.TH
19import Language.Haskell.TH.Quote
20import qualified Language.Haskell.TH.Syntax as TH
22-- | Quote a 'Dynamic' expression. Within the quoted expression, you can use
23-- @$(unqDyn [| x |])@ to refer to any expression @x@ of type @Dynamic t a@; the
24-- unquoted result will be of type @a@
28 let f :: forall d. Data d => d -> StateT [(Name, Exp)] Q d
30 Just (Refl :: d :~: Exp)
31 | AppE (VarE m) eInner <- d
33 -> do n <- lift $ newName "dynamicQuotedExpressionVariable"
37 (e', exprsReversed) <- runStateT (gmapM f e) []
38 let exprs = reverse exprsReversed
39 arg = foldr (\a b -> ConE 'FHCons `AppE` a `AppE` b) (ConE 'FHNil) $ map snd exprs
40 param = foldr (\a b -> ConP 'HCons [VarP a, b]) (ConP 'HNil []) $ map fst exprs
41 [| return $ $(return $ LamE [param] e') <$> distributeFHListOverDynPure $(return arg) |]
43-- | Antiquote a 'Dynamic' expression. This can /only/ be used inside of a
45unqDyn :: Q Exp -> Q Exp
46unqDyn e = [| unqMarker $e |]
48-- | This type represents an occurrence of unqDyn before it has been processed
49-- by qDyn. If you see it in a type error, it probably means that unqDyn has
50-- been used outside of a qDyn context.
53-- unqMarker must not be exported; it is used only as a way of smuggling data
56--TODO: It would be much nicer if the TH AST was extensible to support this kind of thing without trickery
57unqMarker :: a -> UnqDyn
58unqMarker = error "An unqDyn expression was used outside of a qDyn expression"
60-- | Create a 'Dynamic' value using other 'Dynamic's as inputs. The result is
61-- sometimes more concise and readable than the equivalent 'Applicative'-based
62-- expression. For example:
64-- > [mkDyn| $x + $v * $t + 1/2 * $a * $t ^ 2 |]
66-- would have a very cumbersome 'Applicative' encoding.
70 , quotePat = error "mkDyn: pattern splices are not supported"
71 , quoteType = error "mkDyn: type splices are not supported"
72 , quoteDec = error "mkDyn: declaration splices are not supported"
75mkDynExp :: String -> Q Exp
76mkDynExp s = case Hs.parseExpWithMode (Hs.defaultParseMode { Hs.extensions = [ Hs.EnableExtension Hs.TemplateHaskell ] }) s of
77 Hs.ParseFailed (Hs.SrcLoc _ l c) err -> fail $ "mkDyn:" <> show l <> ":" <> show c <> ": " <> err
78 Hs.ParseOk e -> qDyn $ return $ everywhere (id `extT` reinstateUnqDyn) $ Hs.toExp $ everywhere (id `extT` antiE) e
79 where TH.Name (TH.OccName occName) (TH.NameG _ _ (TH.ModName modName)) = 'unqMarker
82 Hs.App (Hs.Var $ Hs.Qual (Hs.ModuleName modName) (Hs.Ident occName)) $ case se of
83 Hs.IdSplice v -> Hs.Var $ Hs.UnQual $ Hs.Ident v
84 Hs.ParenSplice ps -> ps
86 reinstateUnqDyn (TH.Name (TH.OccName occName') (TH.NameQ (TH.ModName modName')))
87 | modName == modName' && occName == occName' = 'unqMarker
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