├── .gitignore ├── PROJECT.md ├── README.md ├── doc └── intro.md ├── project.clj ├── resources └── public │ └── index.html ├── script ├── autobuild ├── cljsrepl └── serve ├── src ├── clj │ └── example │ │ └── routes.clj ├── cljs │ ├── flapjax │ │ └── core.cljs │ ├── jayq │ │ ├── core.cljs │ │ └── util.cljs │ ├── mytest │ │ ├── foo.cljs │ │ └── ui.cljs │ └── repl.cljs ├── extern │ ├── flapjax.js │ └── jquery.js ├── html │ └── index.html └── jslib │ ├── flapjax.js │ └── jquery.js └── test └── lein_test └── core_test.clj /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swn 2 | .*.swo 3 | .*.swp 4 | /target 5 | /lib 6 | /classes 7 | /checkouts 8 | /hlwork 9 | pom.xml 10 | *.jar 11 | *.class 12 | .lein-classpath 13 | .lein-deps-sum 14 | .lein-failures 15 | .lein-plugins 16 | .lein-cljsbuild-repl/ 17 | src/cljs/____* 18 | /resources/public/main.js 19 | /resources/public/out/ 20 | -------------------------------------------------------------------------------- /PROJECT.md: -------------------------------------------------------------------------------- 1 | # HLisp Starter 2 | 3 | HLisp is a lisp implementation built atop 4 | [ClojureScript](https://github.com/clojure/clojurescript/wiki) that attempts to 5 | mitigate several significant problems with interactive web development. A 6 | prototype implementation demo can be viewed 7 | [here](http://micha.github.com/hlisp-starter/). 8 | 9 | ## Motivation, Project Goals 10 | 11 | This project aims to address some of the causes of incidental complexity in 12 | frontend (user interface) web development. 13 | 14 | * **Too many disparate domains.** 15 | 16 | The programmer must manage too many tightly coupled, fundamentally 17 | incompatible subsystems: HTML markup, CSS rules, JavaScript behaviors/events, 18 | HTML templating tools, etc. The HTML itself may be generated by server 19 | side code that the programmer must write in yet another programming language. 20 | 21 | These domains do not have a common set of primitives, means of abstraction, 22 | or means of composition. This results in having no coherent _meaning_ 23 | for entities in these systems: entities do not have a single identity or 24 | way to manage references to them, they can't be composed with each other 25 | in a uniform way. 26 | 27 | The primary technique for managing complexity is the use of modular code and 28 | the separation of concerns. The tight coupling of disparate domains torpedoes 29 | this approach. Concerns which may be orthogonal in one domain may not be 30 | orthogonal in one of the other domains. The ability to create more specific 31 | abstractions by composition of more general ones is greatly restricted. 32 | 33 | **Goal:** Single, unified set of primitives, means of abstraction, and 34 | means of composition. 35 | 36 | * **Pervasive use of global references and shared, mutable state.** 37 | 38 | The lack of a common set of primitives or means of abstraction/composition 39 | dictates the use of global identifiers to pass information between 40 | domains. This could be setting the `id` attribute of an element, or it 41 | could be a more complicated selector-based mechanism. 42 | 43 | **Goal:** Unified evaluation environment and namespace with lexical scope for 44 | all entities. 45 | 46 | * **Callback based event handling.** 47 | 48 | The browser event handling system is designed around a callback 49 | mechanism. Callbacks generally have the void type (aside from those that 50 | return boolean false to cause side effects). Thus, there is no way to 51 | compose them, and they must rely entirely on side effects and shared state 52 | to perform their tasks. 53 | 54 | Event streams are not first-class entities, so there is no way to form 55 | abstractions around them. They can't be composed with each other. They can't 56 | be locally referenced. This forces even more shared state upton the system. 57 | 58 | **Goal:** Push-based event system, first-class event streams, and composable 59 | event handlers. 60 | 61 | ### Additional Requirements 62 | 63 | * **Don't get rid of HTML.** 64 | 65 | Designers will need to work with HTML markup. The browser renders it. The 66 | elimination of HTML markup would necessarily introduce complexity in the 67 | form of an interface between the designer and the programmer, at the very 68 | least. So if possible, keep HTML markup as the primary means of building the 69 | front end DOM structure. 70 | 71 | * **Simple to learn, minimal tooling to get started.** 72 | 73 | The system should be learnable by the motivated designer. They shouldn't have 74 | to be skilled programmers to use it. The system should expose useful 75 | functionality to the user without requiring a lot of boilerplate setup code. 76 | 77 | * **Robust set of libraries.** 78 | 79 | It must be practical to build extensive libraries of modular code. This means 80 | some mechanism for managing references, namespaces, etc. Some way to 81 | distribute libraries and include them in projects is also key. 82 | 83 | ## HTML is Semantically Compatible with Lisp 84 | 85 | To achieve the above goals, it is necessary to perform all front-end processing 86 | in a single, unified evaluation environment. The semantic structure of HTML 87 | suggests a [Lisp](http://en.wikipedia.org/wiki/Lisp_(programming_language) type 88 | language, for the following reasons: 89 | 90 | * **HTML structure is fundamentally lists.** 91 | 92 | A DOM element is semantically a list structure. Tools like 93 | [hiccup](https://github.com/weavejester/hiccup) use this characteristic to 94 | advantage. 95 | 96 | * **DOM appendChild is semantically equivalent to Lisp function application.** 97 | 98 | With one caveat (elaborated below), appending children to a DOM element is 99 | semantically equivalent to Lisp function application. This is also the 100 | means of composition in both systems. 101 | 102 | ## A Possible Solution 103 | 104 | Is Lisp an acceptable environment for the full user interface stack? Does Lisp 105 | provide a solution to the above problems? 106 | 107 | * **The HTML document can be evaluated as a Lisp program.** 108 | 109 | Given that HTML and Lisp are semantically compatible, it's possible to 110 | actually evaluate an HTML document as a Lisp program. The browser could be 111 | made to evaluate the body of the document when the page loads and replace 112 | the body contents with the result. 113 | 114 | * **Lisp provides rich means of abstraction.** 115 | 116 | The abstraction-building capability of Lisp is well known. 117 | 118 | * **Lisp is flexible enough to encompass all of the disparate domains.** 119 | 120 | The power and flexibility of a full-featured Lisp is more than capable of 121 | handling the demands of user interface programming. Templating tools, 122 | event handling, etc. can all be implemented in Lisp. 123 | 124 | * **Evaluating HTML as Lisp unifies the evaluation environment.** 125 | 126 | Since the markup is code that is evaluated in some environment, lexical 127 | scope, namespaced references, and all the other Lisp mechanisms for managing 128 | references is available in both the library code and the markup itself. The 129 | markup elements become first-class entities. 130 | 131 | ## Choice of Lisp Implementation 132 | 133 | If Lisp is to be the environment, the next question is, "Which one?" After some 134 | experimentation ClojureScript was chosen. Possible choices were: 135 | 136 | ### ClojureScript 137 | 138 | [ClojureScript](https://github.com/clojure/clojurescript) is a Lisp that 139 | compiles to JavaScript. 140 | 141 | * [Most of the features of Clojure](https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure). 142 | * [Persistent, immutable data structures, and lazy sequences](http://clojure.org/data_structures). 143 | * Excellent [type system](http://clojure.org/data_structures) with records, 144 | "deftype" types, [protocols](http://clojure.org/protocols), 145 | [multimethods](http://clojure.org/multimethods), etc. 146 | * [Macros](http://clojure.org/macros). (Currently macros are somewhat limited, 147 | but that will probably improve over time.) 148 | * Good JavaScript interoperability. 149 | * [Uses Google's Closure library and compiler](https://github.com/clojure/clojurescript/wiki/Google-Closure). 150 | * Supports aggressive optimization, dead code removal, etc. 151 | * Hlisp compiler can use the Clojure reader to parse forms—it's the same 152 | as the cljs reader. 153 | * There are excellent tools for managing Clojure projects that can be used 154 | immediately to manage hlisp projects. 155 | * A natural choice if the compiler is to be written in Clojure. 156 | 157 | ### LispyScript 158 | 159 | [LispyScript](http://lispyscript.com/) is JavaScript with Lispy syntax and 160 | macros. 161 | 162 | * Excellent JavaScript interop, since it _is_ JavaScript. 163 | * [Macros](http://lispyscript.com/docs/#macros). 164 | * [Monads](http://lispyscript.com/docs/#monads)—the [VX module](http://vxmodules.wikia.com/wiki/What_is_a_VX_module) 165 | of functional programming. Just kidding. 166 | * [Templates](http://lispyscript.com/docs/#templates) 167 | 168 | ### Custom Interpreter 169 | 170 | This approach was tried initially but there were issues with JavaScript 171 | interoperability and performance was not stellar. 172 | 173 | ## Issues 174 | 175 | What are the important issues that must be solved? 176 | 177 | * **Semantic differences between Lisp and HTML.** 178 | 179 | HTML is sort of a [Lisp-1.5](http://en.wikipedia.org/w/index.php?title=Common_Lisp&oldid=402600249#The_function_namespace) 180 | The [car](http://en.wikipedia.org/wiki/CAR_and_CDR) of the list representation 181 | of an HTML element is the tag name. This must be a symbol and can't be another 182 | list. This is a departure from Lisp's uniform treatment of list elements, 183 | where the evaluator evals the car as well as the cdr. HTML semantics can't 184 | express `((f x) y z)`, for example. 185 | 186 | This is a result of the fact that there are no HTML primitives other than the 187 | Element node, which means that all elements are semantically lists. This 188 | makes it impossible to express `(f)` (meaning function application with no 189 | arguments), without giving up the capability to express `f` (function as a 190 | value). 191 | 192 | **Solution:** Give up ability to call functions without arguments from HTML 193 | markup. This can be accounted for by simply requiring that all functions that 194 | are exposed to the user take an argument, even if they discard it. This 195 | preserves the ability to reference functions as values, which is key for the 196 | formation of higher-order functions, and is central to Lisp. In a functional 197 | system, zero-argument functions are rare, as they can only produce side 198 | effects. Additionally, some kind of [funcall](http://www.lispworks.com/documentation/HyperSpec/Body/f_funcal.htm) or [call](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/call) mechanism can be used to accomodate the former case. 199 | 200 | * **Syntactic differences between Lisp and HTML.** 201 | 202 | Clearly, HTML is vastly more verbose than Lisp is. It would be exceedingly 203 | tedious to write a lot of functional code in HTML. A mechanism must be 204 | available by which the programmer can program in Lisp or HTML, as required. 205 | HTML tags also have different syntactic requirements from Lisp symbols. There 206 | are some symbols which are not [valid HTML tags](http://stackoverflow.com/questions/7065693/is-the-at-sign-a-valid-html-xml-tag-character). 207 | 208 | **Solution:** The document `
` must contain a 209 | ` 68 | 69 |
78 | Q. Why did the chicken cross the road?
83 | A. To get to the other side!