1 author: Julien Moutinho <julm+symantic@autogeree.net>
2 bug-reports: Julien Moutinho <julm+symantic@autogeree.net>
9 Library for composing, typing, compiling, transforming and interpreting
10 a custom DSL (Domain-Specific Language) expressing a subset of GHC's Haskell.
11 Its main goal is to enable the runtime handling of terms typed
12 according to some compile-time defined types.
13 The idea being that the more complex logic shall remain coded in Haskell
14 and then this library used to project an interface into a DSL
15 giving runtime users the flexibility to write simpler programs suited to their needs.
19 * Enabling runtime users to enter some Haskell-like expressions
20 without using all the weight and slowness of GHC
21 at runtime (eg. by using <https://hackage.haskell.org/package/hint hint>).
22 * Limiting those expressions to be built from well-controlled expressions only.
23 * Run some analyzes/optimizations on those well-controlled expressions.
27 Please be aware that despite its using of powerful ideas from clever people,
28 this remains a fund-less single-person experimental library.
29 Meaning that it is all but heavily tested and documented,
30 does not have a strong commitment to preserving backward compatibility,
31 and can just die without notice.
32 Its version follows the <http://www.haskell.org/haskellwiki/Package_versioning_policy PVP>,
33 so you may want to use upper-bounds in @build-depends@.
34 This said, hope you'll enjoy the tool :)
38 Reading the boring @Test.hs@ files
39 of <https://hackage.haskell.org/package/symantic-lib symantic-lib>
40 should give you enough examples
41 to understand how to use this library,
42 and reading some of the repetitively boring
43 and painfully repetitive @Lib/*.hs@ files
44 of <https://hackage.haskell.org/package/symantic-lib symantic-lib>
45 should give you some templates and the general pattern
46 to let you extend this library with your own symantics.
48 The @Test.hs@ files use <https://hackage.haskell.org/package/megaparsec megaparsec> as parser
49 and a default grammar somehow sticking to Haskell's, but staying context-free
50 (so in particular: insensitive to the indentation).
51 This grammar, itself written as a symantic embedded DSL,
52 can be reused to build another one,
53 is not bound to a specific parser,
54 and can produce its EBNF rendition.
59 To encode terms in the <http://okmij.org/ftp/tagless-final/ Tagless-Final> way
60 (aka. the /symantic/ way)
61 i.e. to use a /class/ to encode the /syntax/ of terms (eg. 'Sym_Bool')
62 and /class instances/ on a dedicated type to encode their /semantics/
63 (eg. @(Sym_Bool HostI)@ interprets a term as a value of its type
64 in the host language (Haskell here),
65 or @(Sym_Bool TextI)@ interprets a term as a textual rendition, etc.).
67 DSL are then composed by selecting those symantic /classes/.
68 When using symantics for an embedded DSL
69 those /classes/ are all inferred by GHC from the terms used,
70 provided that the @NoMonomorphismRestriction@ extension is on.
71 Otherwise, when using symantics for a non-embedded DSL
72 — the whole point of this library — the /classes/ composing the DSL
73 are selected manually at GHC's compile-time,
74 through the /type-level list/ given to 'compile'.
76 Moreover, the terms are parameterized by the type of the value they encode,
77 in order to get the same type safety as with plain Haskell values.
78 Hence the symantic /classes/ have the higher kind: @((* -> *) -> Constraint)@
79 instead of just @(* -> Constraint)@.
81 Amongst those symantics, 'Sym_Lambda' introduces /lambda abstractions/ by an higher-order approach,
82 meaning that they directly reuse GHC's internal machinery
83 to abstract or instantiate variables,
84 which I think is by far the most efficient and simplest way of doing it
85 (no DeBruijn encoding nor <https://hackage.haskell.org/package/bound bound>'s monads).
87 * __Singleton for any type__.
88 To typecheck terms using a @(Type cs h)@ @GADT@ which acts
89 as a /singleton type/ for any Haskell type @h@
90 buildable by composing the /type constants/ @cs@,
91 each one wrapped inside a @Proxy@ to fit into a common /type-level list/
92 (eg. @cs ~ [Proxy Bool, Proxy (->), Proxy Eq]@).
94 * __Extensible data type__.
95 To inject a type into a /type-level list/
96 or project a /type-level list/ onto a type,
97 to compose an /extensible data type/
98 (eg. the 'Token' @GADT@ gathering the 'TokenT' /data instances/,
99 that a parser can build and then give to 'compile').
100 This type-level programming requires @UndecidableInstances@,
101 but not @OverlappingInstances@.
103 There is a similarity with
104 <http://dx.doi.org/10.1017/S0956796808006758 Data types à la carte>
105 (see for instance <https://hackage.haskell.org/package/compdata compdata>
106 or <https://hackage.haskell.org/package/syntactic syntactic>).
107 Those also enable to compose a DSL using some machinery
108 based upon (co)free(r) (co)monads and (cata|ana)morphisms.
109 Which library fits best your problem domain and brain is for you to judge :)
110 On that topic, see also:
111 <https://www.youtube.com/watch?v=qaAKRxO21fU Stop Paying for Free Monads>.
113 Here, I just came up using /type-level lists/ by hacking
114 <https://hackage.haskell.org/package/glambda glambda>'s @Elem@.
116 * __Extensible class__.
117 To recurse on a /type-level list/ through
118 /class instances/ to compose an /extensible class/
119 (eg. 'CompileR' gathering the 'CompileI' /class instances/,
120 or the more tricky 'Term' /type-level list-zipper/
121 gathering 'Sym_of_Iface' /class instances/
122 while providing in scope the current 'Sym_of_Iface'
123 within each 'Term' built in a 'CompileI' /class instance/).
127 * @GADTs@ for knowing types by pattern-matching terms,
128 or building terms by using type classes.
129 * @Rank2Types@ for parsing @GADT@s.
130 * @TypeInType@ (introduced in GHC 8.0.1)
131 for 'Type' to also bind a kind equality for the type @h@ it encodes.
132 Which makes the /type application/ (':$')
133 give us an /arrow kind/ for the Haskell /type constructor/
134 it applies an Haskell type to, releaving me from tricky workarounds.
135 * @ConstraintKinds@ for @cs@ to contain 'Constraint's,
136 or defining /type synonym/ of /type classes/,
137 or merging /type constraints/.
138 * @DataKinds@ for type-level data structures (eg. /type-level lists/).
139 * @TypeFamilies@ for type-level programming.
140 * @UndecidableInstances@ for type-level programming
141 that may never terminate.
142 * @PolyKinds@ for avoiding a lot of uses of 'Proxy'.
143 * @TypeApplications@ for having a more concise syntax
144 to build 'Type' (eg. @ty \@Bool@).
145 * @DefaultSignatures@ for providing identity transformations of terms,
146 and thus avoid boilerplate code when a transformation
147 does not need to alter all semantics.
148 As explained in <https://ro-che.info/articles/2016-02-03-finally-tagless-boilerplate Reducing boilerplate in finally tagless style>.
152 Your comments, problem reports, or questions are welcome!
154 You have my email address, so… just send me some emails :]
158 * Study to which point /type inferencing/ is doable,
159 so that it would improve the current /type checking/,
160 and remove some type annotations in the DSL.
161 Currently each /lambda abstraction/ must have its variable explicitely typed,
162 and terms must be called with enough arguments to typecheck,
163 be it term arguments (for instance
164 @(+) :: Num a => a -> a -> a@ needs at least one term argument to check @Num a@)
165 or type arguments (for instance
166 @return :: Monad m => a -> m a@ needs a type argument to check @Monad m@).
167 * Study to which point error messages can be improved.
168 * A lot of common terms should be added in @Lib.*@ modules.
169 Maybe as separate packages to limit dependencies.
170 * No transformation is implemented so far,
171 maybe there should be some, at least as examples
172 to demonstrate their power.
173 * Study where to put @INLINE@, @INLINEABLE@ or @SPECIALIZE@ pragmas.
178 license-file: COPYING
179 maintainer: Julien Moutinho <julm+symantic@autogeree.net>
181 stability: experimental
182 synopsis: Library for Typed Tagless-Final Higher-Order Composable DSL
183 tested-with: GHC==8.0.2
184 -- PVP: +-+------- breaking API changes
185 -- | | +----- non-breaking API additions
186 -- | | | +--- code changes with no API change
187 version: 4.3.0.20170409
189 Source-Repository head
190 location: git://git.autogeree.net/symantic
201 MultiParamTypeClasses
212 -fwarn-incomplete-patterns
214 -fprint-explicit-kinds
215 default-language: Haskell2010
218 Language.Symantic.Compiling
219 Language.Symantic.Compiling.Term
220 Language.Symantic.Compiling.Term.Grammar
221 Language.Symantic.Helper.Data.Type.List
222 Language.Symantic.Helper.Data.Type.Peano
223 Language.Symantic.Interpreting
224 Language.Symantic.Interpreting.Dup
225 Language.Symantic.Interpreting.Host
226 Language.Symantic.Interpreting.Text
227 Language.Symantic.Parsing
228 Language.Symantic.Parsing.Token
229 Language.Symantic.Transforming
230 Language.Symantic.Transforming.Trans
231 Language.Symantic.Typing
232 Language.Symantic.Typing.Constant
233 Language.Symantic.Typing.Constraint
234 Language.Symantic.Typing.Family
235 Language.Symantic.Typing.Kind
236 Language.Symantic.Typing.Type