1 -- The default type signature of type class methods are changed
2 -- to introduce a 'LiftDerived'* constraint and the same type class but on the 'Derived' repr,
3 -- this setup avoids to define the method with boilerplate code when its default
4 -- definition with 'liftDerived'* and 'derive' does what is expected by an instance
5 -- of the type class. This is almost as explained in:
6 -- https://ro-che.info/articles/2016-02-03-finally-tagless-boilerplate
7 {-# LANGUAGE DefaultSignatures #-}
8 {-# LANGUAGE DeriveGeneric #-} -- For NFData instances
9 {-# LANGUAGE DeriveAnyClass #-} -- For NFData instances
10 {-# LANGUAGE DeriveLift #-} -- For TH.Lift (Exception tok)
11 {-# LANGUAGE DerivingStrategies #-} -- For UnscopedRegister
12 {-# LANGUAGE StandaloneDeriving #-} -- For Show (Exception (InputToken inp))
13 {-# LANGUAGE InstanceSigs #-}
14 {-# LANGUAGE TemplateHaskell #-}
15 -- | Semantic of the grammar combinators used to express parsers,
16 -- in the convenient tagless-final encoding.
17 module Symantic.Parser.Grammar.Combinators where
19 import Data.Proxy (Proxy(..))
20 import Control.Monad (Monad(..))
21 import Control.DeepSeq (NFData(..))
22 import GHC.Generics (Generic)
23 -- import Data.Set (Set)
24 -- import GHC.TypeLits (KnownSymbol)
25 import Data.Bifunctor (second)
26 import Data.Bool (Bool(..), not, (||))
27 import Data.Char (Char)
28 import Data.Either (Either(..))
29 import Data.Eq (Eq(..))
30 import Data.Function ((.), flip, const, fix)
31 import Data.Ord (Ord(..), Ordering(..))
33 import Data.Kind (Type, Constraint)
34 import Data.Maybe (Maybe(..))
35 import Data.String (String)
36 import Data.Semigroup (Semigroup(..))
37 import Text.Show (Show(..))
38 import Type.Reflection (Typeable, typeRep, eqTypeRep, (:~~:)(..), SomeTypeRep(..))
39 import qualified Data.Functor as Functor
40 import qualified Data.List as List
41 import qualified Language.Haskell.TH as TH
42 import qualified Language.Haskell.TH.Syntax as TH
44 import Symantic.Syntaxes.Derive
45 import qualified Symantic.Syntaxes.Classes as Prod
46 import Symantic.Parser.Grammar.Production
49 type ReprComb = Type -> Type
51 -- * Class 'CombAlternable'
52 class CombAlternable repr where
53 -- | @('alt' es l r)@ parses @(l)@ and return its return value or,
54 -- if it fails with an 'Exception' within @(es)@,
55 -- parses @(r)@ from where @(l)@ has left the input stream,
56 -- and returns its return value,
57 -- otherwise throw the 'Exception' again.
58 alt :: Exception -> repr a -> repr a -> repr a
59 throw :: ExceptionLabel -> repr a
60 -- | @('try' ra)@ records the input stream position,
61 -- then parses like @(ra)@ and either returns its value it it succeeds or fails
62 -- if it fails but with a reset of the input stream to the recorded position.
63 -- Generally used on the first alternative: @('try' rl '<|>' rr)@.
64 try :: repr a -> repr a
66 FromDerived2 CombAlternable repr =>
67 Exception -> repr a -> repr a -> repr a
69 FromDerived CombAlternable repr =>
70 ExceptionLabel -> repr a
72 FromDerived1 CombAlternable repr =>
74 alt = liftDerived2 . alt
75 throw = liftDerived . throw
76 try = liftDerived1 try
78 -- | @(empty)@ parses nothing, always failing to return a value.
81 FromDerived CombAlternable repr =>
83 empty = liftDerived empty
85 -- ** Type 'Exception'
87 = ExceptionLabel ExceptionLabel
90 deriving (Eq, Ord, Show, TH.Lift, Generic, NFData)
91 type ExceptionLabel = String
92 -- type Exceptions = Set Exception
94 -- | Like @('<|>')@ but with different returning types for the alternatives,
95 -- and a return value wrapped in an 'Either' accordingly.
96 (<+>) :: CombApplicable repr => CombAlternable repr => repr a -> repr b -> repr (Either a b)
97 p <+> q = Prod.left <$> p <|> Prod.right <$> q
99 (<|>) :: CombAlternable repr => repr a -> repr a -> repr a
100 (<|>) = alt ExceptionFailure
104 optionally :: CombApplicable repr => CombAlternable repr => repr a -> Production '[] b -> repr b
105 optionally p x = p $> x <|> pure x
107 optional :: CombApplicable repr => CombAlternable repr => repr a -> repr ()
108 optional = flip optionally (Prod.constant ())
110 option :: CombApplicable repr => CombAlternable repr => Production '[] a -> repr a -> repr a
111 option x p = p <|> pure x
113 choice :: CombAlternable repr => [repr a] -> repr a
114 choice = List.foldr (<|>) empty
115 -- FIXME: Here hlint suggests to use Data.Foldable.asum,
116 -- but at this point there is no asum for our own (<|>)
118 maybeP :: CombApplicable repr => CombAlternable repr => repr a -> repr (Maybe a)
119 maybeP p = option Prod.nothing (Prod.just <$> p)
121 manyTill :: CombApplicable repr => CombAlternable repr => repr a -> repr b -> repr [a]
122 manyTill p end = let go = end $> Prod.nil <|> p <:> go in go
124 -- * Class 'CombApplicable'
125 -- | This is like the usual 'Functor' and 'Applicative' type classes
126 -- from the @base@ package, but using @('Production' vs a)@ instead of just @(a)@
127 -- to be able to use and pattern match on some usual terms of type @(a)@ (like 'Prod.id')
128 -- and thus apply some optimizations.
129 -- @(repr)@, for "representation", is the usual tagless-final abstraction
130 -- over the many semantics that this syntax (formed by the methods
131 -- of type class like this one) will be interpreted.
132 class CombApplicable repr where
133 -- | @(a2b '<$>' ra)@ parses like @(ra)@ but maps its returned value with @(a2b)@.
134 (<$>) :: Production '[] (a -> b) -> repr a -> repr b
135 (<$>) f = (pure f <*>)
136 (<$>%) :: (Production '[] a -> Production '[] b) -> repr a -> repr b
137 a2b <$>% ma = Prod.lam a2b <$> ma
139 -- | Like '<$>' but with its arguments 'flip'-ped.
140 (<&>) :: repr a -> Production '[] (a -> b) -> repr b
143 -- | @(a '<$' rb)@ parses like @(rb)@ but discards its returned value by replacing it with @(a)@.
144 (<$) :: Production '[] a -> repr b -> repr a
147 -- | @(ra '$>' b)@ parses like @(ra)@ but discards its returned value by replacing it with @(b)@.
148 ($>) :: repr a -> Production '[] b -> repr b
151 -- | @('pure' a)@ parses the empty string, always succeeding in returning @(a)@.
152 pure :: Production '[] a -> repr a
154 FromDerived CombApplicable repr =>
155 Production '[] a -> repr a
156 pure = liftDerived . pure
158 -- | @(ra2b '<*>' ra)@ parses sequentially @(ra2b)@ and then @(ra)@,
159 -- and returns the application of the function returned by @(ra2b)@
160 -- to the value returned by @(ra)@.
161 (<*>) :: repr (a -> b) -> repr a -> repr b
163 FromDerived2 CombApplicable repr =>
164 repr (a -> b) -> repr a -> repr b
165 (<*>) = liftDerived2 (<*>)
167 -- | @(ra '<*' rb)@ parses sequentially @(ra)@ and then @(rb)@,
168 -- and returns like @(ra)@, discarding the return value of @(rb)@.
169 (<*) :: repr a -> repr b -> repr a
170 (<*) = liftA2 Prod.const
172 -- | @(ra '*>' rb)@ parses sequentially @(ra)@ and then @(rb)@,
173 -- and returns like @(rb)@, discarding the return value of @(ra)@.
174 (*>) :: repr a -> repr b -> repr b
175 x *> y = (Prod.id <$ x) <*> y
177 -- | Like '<*>' but with its arguments 'flip'-ped.
178 (<**>) :: repr a -> repr (a -> b) -> repr b
179 (<**>) = liftA2 (Prod.flip Prod..@ (Prod.$))
181 (<**>) :: repr a -> repr (a -> b) -> repr b
182 (<**>) = liftA2 (\a f -> f a)
184 -- | @('liftA2' a2b2c ra rb)@ parses sequentially @(ra)@ and then @(rb)@,
185 -- and returns the application of @(a2b2c)@ to the values returned by those parsers.
186 liftA2 :: Production '[] (a -> b -> c) -> repr a -> repr b -> repr c
187 liftA2 f x = (<*>) (f <$> x)
189 infixl 4 <*>, <*, *>, <**>
194 (<:>) :: CombApplicable repr => repr a -> repr [a] -> repr [a]
195 (<:>) = liftA2 Prod.cons
197 sequence :: CombApplicable repr => [repr a] -> repr [a]
198 sequence = List.foldr (<:>) (pure Prod.nil)
200 traverse :: CombApplicable repr => (a -> repr b) -> [a] -> repr [b]
201 traverse f = sequence . List.map f
202 -- FIXME: Here hlint suggests to use Control.Monad.mapM,
203 -- but at this point there is no mapM for our own sequence
205 repeat :: CombApplicable repr => Int -> repr a -> repr [a]
206 repeat n p = traverse (const p) [1..n]
208 between :: CombApplicable repr => repr o -> repr c -> repr a -> repr a
209 between open close p = open *> p <* close
211 void :: CombApplicable repr => repr a -> repr ()
214 unit :: CombApplicable repr => repr ()
215 unit = pure (Prod.constant ())
217 -- * Class 'CombFoldable'
218 class CombFoldable repr where
219 chainPre :: repr (a -> a) -> repr a -> repr a
220 chainPost :: repr a -> repr (a -> a) -> repr a
221 chainPre = liftDerived2 chainPre
222 chainPost = liftDerived2 chainPost
224 FromDerived2 CombFoldable repr =>
225 repr (a -> a) -> repr a -> repr a
227 FromDerived2 CombFoldable repr =>
228 repr a -> repr (a -> a) -> repr a
231 CombApplicable repr =>
232 CombAlternable repr =>
233 repr (a -> a) -> repr a -> repr a
235 CombApplicable repr =>
236 CombAlternable repr =>
237 repr a -> repr (a -> a) -> repr a
238 chainPre op p = go <*> p where go = (Prod..) <$> op <*> go <|> pure Prod.id
239 chainPost p op = p <**> go where go = (Prod..) <$> op <*> go <|> pure Prod.id
242 chainPre op p = flip (foldr ($)) <$> many op <*> p
243 chainPost p op = foldl' (flip ($)) <$> p <*> many op
247 conditional :: CombSelectable repr => [(Production '[] (a -> Bool), repr b)] -> repr a -> repr b -> repr b
248 conditional cs p def = match p fs qs def
249 where (fs, qs) = List.unzip cs
254 CombApplicable repr => CombFoldable repr =>
255 Production '[] (a -> b -> b) -> Production '[] b -> repr a -> repr b
256 pfoldr f k p = chainPre (f <$> p) (pure k)
259 CombApplicable repr => CombFoldable repr =>
260 Production '[] (a -> b -> b) -> Production '[] b -> repr a -> repr b
261 pfoldr1 f k p = f <$> p <*> pfoldr f k p
264 CombApplicable repr => CombFoldable repr =>
265 Production '[] (b -> a -> b) -> Production '[] b -> repr a -> repr b
266 pfoldl f k p = chainPost (pure k) ((Prod.flip <$> pure f) <*> p)
269 CombApplicable repr => CombFoldable repr =>
270 Production '[] (b -> a -> b) -> Production '[] b -> repr a -> repr b
271 pfoldl1 f k p = chainPost (f <$> pure k <*> p) ((Prod.flip <$> pure f) <*> p)
275 CombApplicable repr => CombFoldable repr =>
276 Production '[] (a -> b) -> repr a -> repr (b -> a -> b) -> repr b
277 chainl1' f p op = chainPost (f <$> p) (Prod.flip <$> op <*> p)
280 CombApplicable repr => CombFoldable repr =>
281 repr a -> repr (a -> a -> a) -> repr a
282 chainl1 = chainl1' Prod.id
285 chainr1' :: ParserOps rep => rep (a -> b) -> repr a -> repr (a -> b -> b) -> repr b
286 chainr1' f p op = newRegister_ Prod.id $ \acc ->
287 let go = bind p $ \x ->
288 modify acc (Prod.flip (Prod..@) <$> (op <*> x)) *> go
292 chainr1 :: repr a -> repr (a -> a -> a) -> repr a
293 chainr1 = chainr1' Prod.id
295 chainr :: repr a -> repr (a -> a -> a) -> Production '[] a -> repr a
296 chainr p op x = option x (chainr1 p op)
300 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
301 repr a -> repr (a -> a -> a) -> Production '[] a -> repr a
302 chainl p op x = option x (chainl1 p op)
304 -- Derived Combinators
306 CombApplicable repr => CombFoldable repr =>
308 many = pfoldr Prod.cons Prod.nil
311 CombApplicable repr => CombFoldable repr =>
312 Int -> repr a -> repr [a]
313 manyN n p = List.foldr (const (p <:>)) (many p) [1..n]
316 CombApplicable repr => CombFoldable repr =>
321 CombApplicable repr => CombFoldable repr =>
323 --skipMany p = let skipManyp = p *> skipManyp <|> unit in skipManyp
324 skipMany = void . pfoldl Prod.const Prod.unit -- the void here will encourage the optimiser to recognise that the register is unused
327 CombApplicable repr => CombFoldable repr =>
328 Int -> repr a -> repr ()
329 skipManyN n p = List.foldr (const (p *>)) (skipMany p) [1..n]
332 CombApplicable repr => CombFoldable repr =>
334 skipSome = skipManyN 1
337 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
338 repr a -> repr b -> repr [a]
339 sepBy p sep = option Prod.nil (sepBy1 p sep)
342 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
343 repr a -> repr b -> repr [a]
344 sepBy1 p sep = p <:> many (sep *> p)
347 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
348 repr a -> repr b -> repr [a]
349 endBy p sep = many (p <* sep)
352 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
353 repr a -> repr b -> repr [a]
354 endBy1 p sep = some (p <* sep)
357 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
358 repr a -> repr b -> repr [a]
359 sepEndBy p sep = option Prod.nil (sepEndBy1 p sep)
362 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
363 repr a -> repr b -> repr [a]
365 let seb1 = p <**> (sep *> (Prod.flip Prod..@ Prod.cons <$> option Prod.nil seb1)
366 <|> pure (Prod.flip Prod..@ Prod.cons Prod..@ Prod.nil))
370 sepEndBy1 :: repr a -> repr b -> repr [a]
371 sepEndBy1 p sep = newRegister_ Prod.id $ \acc ->
372 let go = modify acc ((Prod.flip (Prod..)) Prod..@ Prod.cons <$> p)
373 *> (sep *> (go <|> get acc) <|> get acc)
374 in go <*> pure Prod.nil
377 -- * Class 'CombMatchable'
378 class CombMatchable repr where
380 repr a -> [(Production '[] (a -> Bool), repr b)] -> repr b -> repr b
381 conditional a bs = liftDerived1
382 (conditional (derive a) (second derive Functor.<$> bs))
383 default conditional ::
384 FromDerived1 CombMatchable repr => Derivable repr =>
385 repr a -> [(Production '[] (a -> Bool), repr b)] -> repr b -> repr b
388 CombMatchable repr =>
390 repr a -> [Production '[] a] -> (Production '[] a -> repr b) -> repr b -> repr b
391 match a as p = conditional a
393 ( Prod.lam (v Prod.==)
399 CombMatchable repr =>
400 Production '[] (a -> Bool) -> repr a -> repr b -> repr b -> repr b
401 predicate p a b = conditional a [(p, b)]
405 CombMatchable repr =>
406 repr Bool -> (repr a, repr a) -> repr a
407 cond <?:> (p, q) = predicate Prod.id cond p q
409 -- * Class 'CombSatisfiable'
410 class CombSatisfiable tok repr where
411 satisfy :: Production '[] (tok -> Bool) -> repr tok
413 FromDerived (CombSatisfiable tok) repr =>
414 Production '[] (tok -> Bool) -> repr tok
415 satisfy = liftDerived . satisfy
417 -- | Global 'TH.Name' to refer to the @(InputToken inp)@ type
418 -- from TemplateHaskell code.
419 inputTokenProxy :: TH.Name
420 inputTokenProxy = TH.mkName "inputToken"
423 CombApplicable repr =>
424 CombSatisfiable Char repr =>
426 char c = satisfy (Prod.equal Prod..@ Prod.constant c) $> Prod.constant c
428 item :: forall tok repr.
429 Ord tok => Show tok => Typeable tok => TH.Lift tok => NFData tok =>
430 CombSatisfiable tok repr => repr tok
431 item = satisfy (Prod.const Prod..@ Prod.constant True)
434 CombAlternable repr =>
435 CombSatisfiable Char repr =>
440 CombApplicable repr => CombAlternable repr =>
441 CombSatisfiable Char repr =>
442 [Char] -> repr [Char]
443 string = try . traverse char
446 Ord tok => Show tok => Typeable tok => TH.Lift tok => NFData tok =>
447 CombSatisfiable tok repr =>
449 oneOf ts = satisfy (production (`List.elem` ts) [||\t -> $$(ofChars ts [||t||])||])
452 (Ord tok, Show tok, TH.Lift tok, NFData tok, Typeable tok) =>
453 CombSatisfiable tok repr =>
455 noneOf ts = satisfy (production (not . (`List.elem` ts)) [||\c -> not $$(ofChars ts [||c||])||])
458 TH.Lift tok => Eq tok =>
459 {-alternatives-}[tok] ->
460 {-input-}TH.CodeQ tok ->
463 (\tok acc inp -> [|| tok == $$inp || $$(acc inp) ||])
467 CombAlternable repr =>
468 CombApplicable repr =>
469 CombSatisfiable Char repr =>
470 CombLookable repr => repr ()
471 more = look (void (item @Char))
474 (Ord tok, Show tok, TH.Lift tok, NFData tok, Typeable tok) =>
475 CombAlternable repr =>
476 CombApplicable repr =>
477 CombSatisfiable tok repr =>
479 token tok = satisfy (Prod.equal Prod..@ Prod.constant tok) $> Prod.constant tok
480 -- token tok = satisfy [ExceptionToken tok] (Prod.eq Prod..@ Prod.qual Prod..@ Prod.char tok) $> Prod.char tok
483 (Ord tok, Show tok, TH.Lift tok, NFData tok, Typeable tok) =>
484 CombApplicable repr => CombAlternable repr =>
485 CombSatisfiable tok repr => [tok] -> repr [tok]
486 tokens = try . traverse token
488 -- * Class 'CombSelectable'
489 class CombSelectable repr where
490 branch :: repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
492 FromDerived3 CombSelectable repr =>
493 repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
494 branch = liftDerived3 branch
497 CombMatchable repr =>
498 CombSelectable repr =>
499 Prod.Constantable () repr =>
500 repr Bool -> repr () -> repr ()
501 when p q = p <?:> (q, Prod.constant ())
504 CombMatchable repr =>
505 CombSelectable repr =>
506 Prod.Constantable () repr =>
508 while x = fix (when x)
510 -- * Class 'CombLookable'
511 class CombLookable repr where
512 look :: repr a -> repr a
514 -- Note: following [Error Reporting in Parsing Expression Grammars](https://arxiv.org/abs/1405.6646v3)
515 -- what happens inside a 'negLook' does not take part in error reporting at
516 -- all, which is the simplest approach, and also gives a consistent result
517 -- for: @(negLook . negLook)@.
518 negLook :: repr a -> repr ()
520 FromDerived1 CombLookable repr =>
523 FromDerived1 CombLookable repr =>
525 look = liftDerived1 look
526 negLook = liftDerived1 negLook
529 eof = liftDerived eof
531 FromDerived CombLookable repr =>
533 -- eof = negLook (satisfy @Char (Prod.const Prod..@ Prod.bool True))
536 -- Composite Combinators
537 -- someTill :: repr a -> repr b -> repr [a]
538 -- someTill p end = negLook end *> (p <:> manyTill p end)
541 constp :: CombApplicable repr => repr a -> repr (b -> a)
542 constp = (Prod.const <$>)
547 (>>) :: CombApplicable repr => repr a -> repr b -> repr b
550 -- Monoidal Operations
553 (<~>) :: CombApplicable repr => repr a -> repr b -> repr (a, b)
554 (<~>) = liftA2 (Prod.runtime (,))
557 (<~) :: CombApplicable repr => repr a -> repr b -> repr a
561 (~>) :: CombApplicable repr => repr a -> repr b -> repr b
566 CombApplicable repr =>
567 Production '[] (a -> b -> c) -> repr a -> repr b -> repr c
568 liftA2 f x = (<*>) (fmap f x)
571 CombApplicable repr =>
572 Production '[] (a -> b -> c -> d) -> repr a -> repr b -> repr c -> repr d
573 liftA3 f a b c = liftA2 f a b <*> c
578 -- Combinators interpreters for 'Sym.Any'.
579 instance CombApplicable repr => CombApplicable (Sym.Any repr)
580 instance CombSatisfiable repr => CombSatisfiable (Sym.Any repr)
581 instance CombAlternable repr => CombAlternable (Sym.Any repr)
582 instance CombSelectable repr => CombSelectable (Sym.Any repr)
583 instance CombMatchable repr => CombMatchable (Sym.Any repr)
584 instance CombLookable repr => CombLookable (Sym.Any repr)
585 instance CombFoldable repr => CombFoldable (Sym.Any repr)
589 newtype Register r a = Register { unRegister :: UnscopedRegister a }
592 -- ** Type 'UnscopedRegister'
593 newtype UnscopedRegister r = UnscopedRegister { unUnscopedRegister :: TH.Name }
595 deriving newtype Show
599 put_ :: ParserOps rep => Register r a -> rep a -> Parser ()
600 put_ r = put r . pure
602 gets_ :: ParserOps rep => Register r a -> rep (a -> b) -> Parser b
603 gets_ r = gets r . pure
605 modify_ :: ParserOps rep => Register r a -> rep (a -> a) -> Parser ()
606 modify_ r = modify r . pure
610 CombApplicable repr =>
611 CombRegisterable repr =>
612 Register r a -> repr (a -> b) -> repr b
613 gets r p = p <*> get r
616 CombApplicable repr =>
617 CombRegisterable repr =>
618 Register r a -> repr (a -> a) -> repr ()
619 modify r p = put r (gets r p)
622 CombRegisterable repr =>
623 Register r1 a -> Register r2 a -> repr ()
624 move dst src = put dst (get src)
627 CombRegisterable repr =>
628 repr a -> (repr a -> repr b) -> repr b
629 bind p f = new p (f . get)
632 CombApplicable repr =>
633 CombRegisterable repr =>
634 Register r a -> repr a -> repr b -> repr b
635 local r p q = bind (get r) (\x -> put r p *> q <* put r x)
638 CombApplicable repr =>
639 CombRegisterable repr =>
640 Register r1 a -> Register r2 a -> repr ()
641 swap r1 r2 = bind (get r1) (\x -> move r1 r2 *> put r2 x)
644 CombAlternable repr =>
645 CombApplicable repr =>
646 CombRegisterable repr =>
647 Register r a -> repr b -> repr b
648 rollback r p = bind (get r) (\x -> p <|> put r x *> empty)
651 CombApplicable repr =>
652 CombMatchable repr =>
653 CombSelectable repr =>
654 CombRegisterable repr =>
655 Prod.Constantable () repr =>
656 repr a -> repr (a -> Bool) -> repr (a -> a) -> repr () -> repr ()
657 for init cond step body =
659 let cond' = gets i cond in
660 when cond' (while (body *> modify i step *> cond'))
664 -- ** Class 'CombRegisterable'
665 class CombRegisterable (repr::ReprComb) where
666 new :: repr a -> (forall r. Register r a -> repr b) -> repr b
667 get :: Register r a -> repr a
668 put :: Register r a -> repr a -> repr ()
670 FromDerived CombRegisterable repr => Derivable repr =>
671 repr a -> (forall r. Register r a -> repr b) -> repr b
673 FromDerived CombRegisterable repr =>
674 Register r a -> repr a
676 FromDerived1 CombRegisterable repr =>
677 Register r a -> repr a -> repr ()
678 new ini f = liftDerived (new (derive ini) (derive . f))
679 get = liftDerived . get
680 put = liftDerived1 . put