66[ ![ Clojars Project] ( https://img.shields.io/clojars/v/dhall-clj/dhall-clj.svg )] ( https://clojars.org/dhall-clj/dhall-clj )
77[ ![ cljdoc badge] ( https://cljdoc.xyz/badge/dhall-clj/dhall-clj )] ( https://cljdoc.xyz/d/dhall-clj/dhall-clj/CURRENT )
88
9- Compiler from Dhall to Clojure.
9+ ## Dhall + Clojure = 😍
1010
11- ## Dhall?
11+ This package allows you to compile [ Dhall] [ dhall ] expressions to Clojure expressions.
1212
13- [ Dhall ] [ dhall ] is a functional programming language that is not Turing complete.
13+ And this is a very useful thing! Why is it so?
1414
15- * You can think of Dhall as: JSON + functions + types + imports.*
15+ Some use cases for Dhall are:
16+ - ** typed configurations** : you need your configuration/data to have a precise type
17+ - ** templating** : template things in a sane way (you definitely don't want a Turing complete
18+ templating language..)
19+ - send code on the wire in ** safe** and ** efficient** way: it's safe because the language is not
20+ Turing complete, and it's efficient because Dhall defines a binary encoding to serialize and
21+ deserialize expressions.
22+
23+ If this sounds useful to you too, then read on! For more inspiration about possible use cases, you can
24+ take a look at the wiki page [ "Using Dhall in Production"] [ dhall-production ] tracking the usage of
25+ Dhall in the wild.
1626
17- For a Dhall Tutorial, see the [ README of the project ] [ dhall ] , or the [ full tutorial ] [ dhall-tutorial ] .
27+ ### Sounds nice! But where can I read more about this Dhall?
1828
19- The purpose of this library is to consume Dhall expressions from Clojure.
29+ First of all, a quick definition: [ Dhall] [ dhall ] is a functional programming language that is not
30+ Turing complete, geared towards practical usage as a configuration language.
2031
21- Example use cases for Dhall are:
22- - typed configuration files
23- - templating
24- - safe exchange format (since the Language Standard defines an efficient binary encoding)
32+ * You can think of Dhall as: JSON + functions + types + imports.*
2533
26- For more inspiration about possible use cases, see the wiki page
27- [ Using Dhall in Production] [ dhall-production ] .
34+ For a more detailed pitch and a live demo, the [ Dhall website] [ dhall ] is the best place to start.
35+ If you'd like a Dhall tutorial instead, see the [ README of the project] [ dhall-repo ] ,
36+ or the [ full tutorial] [ dhall-tutorial ] .
2837
29- ## Dhall version
38+ ### Dhall Language Version and compliance to the Standard
3039
3140* Note: this is quite alpha. Things might be broken, so don't hesitate to [ open an issue] [ issues ] .*
3241
33- We basically support all of Dhall ` v2.0.0 ` , except the following:
34- - [ #7 ] ( ../../issues/7 ) : Http imports
35- - [ #4 ] ( ../../issues/4 ) : Binary serialization/deserialization
36- - [ #5 ] ( ../../issues/5 ) : Imports semantic integrity checks (hashing)
37- - [ #8 ] ( ../../issues/8 ) : Caching of hashed imports
38- - [ #12 ] ( ../../issues/12 ) : The import alternative operator ` ? `
39- - The Dhall compilation works otherwise, but the translation to Clojure data structures is partial for now, e.g. no ` Natural/build `
42+ Dhall has a versioned [ language specification] [ dhall-repo ] , so it's useful to know which version we are using.
43+
44+ This library implements ` v5.0.0 ` of Dhall, except for http imports: that is, you cannot import things via
45+ http URLs yet.
46+
47+ Moreover, the translation to Clojure data structures is somewhat partial for now, so be extra careful when
48+ checking that the data you get from Dhall is what you expected.
49+
50+ For more information on the aspects in which this implementation is not compliant with the Standard, see
51+ the issues labeled with [ "standard compliance"] [ standard-compliance-issues ] .
4052
4153## HOWTO
4254
4355``` clojure
44- (require [dhall-clojure.core :refer [input input-ast]])
56+ (require ' [dhall-clojure.core :refer [input input-ast]])
4557
46- ; ; We can run Dhall expression with the `input` function
58+ ; ; We can run compile and run Dhall expression in Clojure with the `input` function.
59+ ; ; Note that the result of the evaluation is a Clojure value
4760
4861(input " True && False" )
49-
5062; ; => false
5163
5264
53- ; ; We can even import functions from Dhall, and execute them:
65+ ; ; We can even import functions from Dhall..
66+ ; ; (the following compiles a Dhall function into a Clojure function)
5467
5568(def build-info (input " λ(major : Natural) → { version = \" ${Natural/show major}.0\" }" ))
69+
70+ ; ; ..and run them in Clojure!
71+
5672(build-info 1 )
5773
5874; ; => {"version" "1.0"}
@@ -71,6 +87,86 @@ We basically support all of Dhall `v2.0.0`, except the following:
7187; ; => #dhall_clj.ast.NaturalLit {:n 2}
7288```
7389
90+ ## HOWTO - Advanced usage
91+
92+ There are cases in which you'd need to run single compiler phases, e.g. if you wish to
93+ serialize expressions.
94+
95+ If we follow the lifetime of a Dhall expression being compiled, we'll see the following
96+ phases happening:
97+ - ** parsing** : here we go from "text" to Abstract Syntax Tree (AST), that is going to be the
98+ representation we'll use for the Dhall expression in all the next phases.
99+ That is, all the following operations are defined as manipulations on the AST.
100+ - ** import resolution** : a Dhall expression might contain local and remote imports (files,
101+ environment variables, http URLs), so we should try to resolve these imports and incorporate
102+ them into the expression before going forward (as we cannot verify the type of the expression
103+ if we don't know what the import will contain).
104+ So this phase will transform the AST containing imports into a import-free AST
105+ - ** typechecking** : once we have the full expression, we have to verify that the types are correct,
106+ e.g. we'll check that if a function takes an ` Integer ` it's not being passed a ` Text ` , and so on.
107+ - ** execution/normalization** : this is the final phase of the compilation, and effectively "runs"
108+ the computation. We do this by "reducing to a normal form" (all Dhall expression have a "normal form",
109+ and this means that all expressions * always* terminate), where we basically apply all the functions
110+ we can apply.
111+ - (optionally) ** emit Clojure** : this phase is not strictly included in the compilation, but it will
112+ transform the Dhall AST from the normalization into Clojure datastructures. E.g. Dhall Lists will
113+ become Clojure vectors, Records will become Clojure maps, Dhall functions will become Clojure functions,
114+ etc.
115+
116+ Let's see how to use this knowledge to do interesting things (like serializing Dhall expressions to binary):
117+ ``` clojure
118+ ; ; There are different namespaces for every compilation phase:
119+ ; ; - "parsing"
120+ (require '[dhall-clj.parse :refer [parse expr]])
121+
122+ ; ; - "import resolution" (the `state` ns is for the in-memory cache for imports)
123+ (require '[dhall-clj.import :refer [resolve-imports]])
124+ (require '[dhall-clj.state :as s])
125+
126+ ; ; - "typechecking"
127+ (require '[dhall-clj.typecheck :refer [typecheck]])
128+
129+ ; ; - "normalization"
130+ (require '[dhall-clj.beta-normalize :refer [beta-normalize]])
131+
132+ ; ; - "emit Clojure"
133+ (require '[dhall-clj.emit :refer [emit]])
134+
135+ ; ; See the implementation of `dhall-clj.core/input` to see how to compose them together properly
136+ ; ; But we can say that a basic re-implementation of `input` would be:
137+
138+ (defn my-input [dhall-text]
139+ (let [parse-tree (parse dhall-code)
140+ ast (expr parse-tree)
141+ ast (resolve-imports ast (s/new ))
142+ type (typecheck ast {})
143+ ast (beta-normalize ast)
144+ clj-sexp (emit ast)]
145+ (eval clj-sexp)))
146+
147+
148+ ; ; Let's say we now want to serialize a Dhall expression to binary data.
149+ ; ; We'll take the `build-info` function we used in the previous section to demonstrate this
150+
151+ (def dhall-source " λ(major : Natural) → { version = \" ${Natural/show major}.0\" }" )
152+
153+ (require '[dhall-clj.binary :refer [encode decode]])
154+
155+ (def serialized (-> dhall-source input-ast encode))
156+
157+ ; ; Now `serialized` will contain the serialized expression in a ByteArray.
158+ ; ; You can now send this around, and when you want to _deserialize_ an encoded
159+ ; ; expression you can run `decode` on it:
160+
161+ (def build-info (-> serialized decode emit eval))
162+
163+ ; ; ...and you can now run this code as well!
164+
165+ (build-info 1 )
166+
167+ ; ; => {"version" "1.0"}
168+ ```
169+
74170## Catching exceptions
75171
76172Sometimes the evaluation will fail, and we'd like to catch the error condition to handle that.
@@ -121,10 +217,12 @@ Distributed under the
121217[ Eclipse Public License] ( http://www.eclipse.org/legal/epl-v10.html ) ,
122218the same as Clojure.
123219
124- [ dhall ] : https://github.com/dhall-lang/dhall-lang
125- [ dhall-tutorial ] : http://hackage.haskell.org/package/dhall-1.17.0/docs/Dhall-Tutorial.html
220+ [ dhall ] : https://dhall-lang.org
221+ [ dhall-repo ] : https://github.com/dhall-lang/dhall-lang
222+ [ dhall-tutorial ] : http://hackage.haskell.org/package/dhall-1.20.1/docs/Dhall-Tutorial.html
126223[ dhall-production ] : https://github.com/dhall-lang/dhall-lang/wiki/Dhall-in-production
127224[ issues ] : https://github.com/f-f/dhall-clj/issues
128225[ ex ] : https://github.com/mpenet/ex
129226[ ex-info ] : https://clojuredocs.org/clojure.core/ex-info
130227[ fail ] : ./src/dhall_clj/fail.clj
228+ [ standard-compliance-issues ] : https://github.com/f-f/dhall-clj/issues?q=is%3Aissue+is%3Aopen+label%3A%22standard+compliance%22
0 commit comments