<?xml version='1.0' encoding='UTF-8'?>
<rss version='2.0' xmlns:atom='http://www.w3.org/2005/Atom'>
<channel>
<atom:link href='http://code.thosmos.com/' rel='self' type='application/rss+xml'/>
<title>
Coding the Thosmos
</title>
<link>
http://code.thosmos.com/
</link>
<description>

</description>
<lastBuildDate>
Tue, 14 Jan 2020 22:08:36 -0800
</lastBuildDate>
<generator>
clj-rss
</generator>
<item>
<guid>
http://code.thosmos.com/posts/2020-01-14-should-threading-macros-handle-lambdas.html
</guid>
<link>
http://code.thosmos.com/posts/2020-01-14-should-threading-macros-handle-lambdas.html
</link>
<title>
Should Threading Macros Handle Lambdas?
</title>
<description>
&lt;p&gt;I recently thought I ran into a bug in &lt;code&gt;clojure.spec&lt;/code&gt; because it threw an exception when I put a lambda like &lt;code&gt;&amp;#40;fn &amp;#91;x&amp;#93; x&amp;#41;&lt;/code&gt; or &lt;code&gt;#&amp;#40;identity %&amp;#41;&lt;/code&gt; into the &lt;code&gt;-&amp;gt;&lt;/code&gt; threading macro without wrapping it first in an extra parens like &lt;code&gt;&amp;#40;&amp;#40;fn &amp;#91;x&amp;#93; x&amp;#41;&amp;#41;&lt;/code&gt;.  This is the most common repeated &quot;mistake&quot; I've made in Clojure over the years, and I've heard from others that it's a common misconception about the threading macros.  This &quot;mistake&quot; in my case is based on my assumption that the lambda is a fundamental &quot;thing&quot; or value in the language.  But, in fact, Clojure is just data, mostly macros, and each macro handles its input data in different ways.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;-&amp;gt;&lt;/code&gt; threading macro treats a lambda as a list instead of as a fundamental &quot;function value.&quot;  When one does &lt;code&gt;&amp;#40;-&amp;gt; :hmm &amp;#40;fn &amp;#91;x&amp;#93; x&amp;#41;&amp;#41;&lt;/code&gt; it is expanded like: &lt;code&gt;&amp;#40;fn :hmm &amp;#91;x&amp;#93; x&amp;#41;&lt;/code&gt; which obviously is not what is intended.   &lt;em&gt;However&lt;/em&gt;, it does have a special convenience case for a non-list thing like a symbol, keyword, etc, which it assumes is something that can behave as a function with one argument, and wraps it in parens before threading.  This special case adds value because it interprets the &lt;em&gt;intention&lt;/em&gt; of the user and avoids forcing them to add parens when they're unnecessary. &lt;/p&gt;&lt;p&gt;I assert that the basic lambda forms &lt;code&gt;&amp;#40;fn&amp;#41;&lt;/code&gt; and &lt;code&gt;#&amp;#40;&amp;#41;&lt;/code&gt; should and easily can be handled similarly to a symbol, by interpreting the &lt;em&gt;intention&lt;/em&gt; of the user.  The value from doing so would make the threading macros simpler and more intuitive to use, would remove an unnecessary exception that affects numerous users,  and would advance the language towards treating the lambda forms as core &quot;values.&quot;  This last point is a philosophical one, but important in my opinion for making the language &quot;just work&quot; the way a new or non-expert user expects when getting stuff done.&lt;/p&gt;&lt;p&gt;The existing special case of wrapping a non-list form already demonstrates the value of providing some interpretation of the &lt;em&gt;intention&lt;/em&gt; of the user, but there now exists an inconsistency between this special case, and the absence of it for two of the most common forms of arguably one of the most foundational &quot;values&quot; in the language, the function itself.&lt;/p&gt;&lt;p&gt;Have you been bitten by this &quot;mistake&quot;?&lt;/p&gt;&lt;p&gt;If you'd like to try it side by side with the existing &lt;code&gt;-&amp;gt;&lt;/code&gt; macro, here's a version called &lt;code&gt;t-&amp;gt;&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&amp;#40;defmacro t-&amp;gt;
  &amp;quot;Threads the expr through the forms. Inserts x as the
  second item in the first form, making a list of it if it is a lambda or not a
  list already. If there are more forms, inserts the first form as the
  second item in second form, etc.&amp;quot;
  {:added &amp;quot;1.0&amp;quot;}
  &amp;#91;x &amp;amp; forms&amp;#93;
  &amp;#40;loop &amp;#91;x x, forms forms&amp;#93;
    &amp;#40;if forms
      &amp;#40;let &amp;#91;form &amp;#40;first forms&amp;#41;
            threaded &amp;#40;if &amp;#40;and &amp;#40;seq? form&amp;#41; &amp;#40;not &amp;#40;#{'fn 'fn&amp;#42;} &amp;#40;first form&amp;#41;&amp;#41;&amp;#41;&amp;#41;
                       &amp;#40;with-meta `&amp;#40;&amp;#126;&amp;#40;first form&amp;#41; &amp;#126;x &amp;#126;@&amp;#40;next form&amp;#41;&amp;#41; &amp;#40;meta form&amp;#41;&amp;#41;
                       &amp;#40;list form x&amp;#41;&amp;#41;&amp;#93;
        &amp;#40;recur threaded &amp;#40;next forms&amp;#41;&amp;#41;&amp;#41;
      x&amp;#41;&amp;#41;&amp;#41;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I've prepared a patch for &lt;code&gt;-&amp;gt;&lt;/code&gt; and &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; that handles this use case and has no breaking impact that I can conceive of, keeping the existing behavior, while adding the new.  It passes all of the core Clojure tests, but I have not yet tested it on outside code beyond my own.  That would obviously be necessary before it could be considered a possible change in core.&lt;br /&gt;   &lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;diff&quot;&gt;From 686831062a574486413022af31e8c7a07b78cd24 Mon Sep 17 00:00:00 2001
From: Thomas Spellman &amp;lt;thos37@gmail.com&amp;gt;
Date: Mon, 13 Jan 2020 20:39:45 -0800
Subject: &amp;#91;PATCH&amp;#93; thread macros

---
 src/clj/clojure/core.clj             | 12 ++++++------
 test/clojure/test&amp;#95;clojure/macros.clj | 12 ++++++++++++
 2 files changed, 18 insertions&amp;#40;+&amp;#41;, 6 deletions&amp;#40;-&amp;#41;

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 8e98e072..fe43289b 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -1670,42 +1670,42 @@
   &amp;#40;. &amp;#40;. System &amp;#40;getProperties&amp;#41;&amp;#41; &amp;#40;get \&amp;quot;os.name\&amp;quot;&amp;#41;&amp;#41;
 
   but is easier to write, read, and understand.&amp;quot;
   {:added &amp;quot;1.0&amp;quot;}
   &amp;#40;&amp;#91;x form&amp;#93; `&amp;#40;. &amp;#126;x &amp;#126;form&amp;#41;&amp;#41;
   &amp;#40;&amp;#91;x form &amp;amp; more&amp;#93; `&amp;#40;.. &amp;#40;. &amp;#126;x &amp;#126;form&amp;#41; &amp;#126;@more&amp;#41;&amp;#41;&amp;#41;
 
 &amp;#40;defmacro -&amp;gt;
-  &amp;quot;Threads the expr through the forms. Inserts x as the
-  second item in the first form, making a list of it if it is not a
+  &amp;quot;Threads the expr through the forms. Inserts x as the second item
+  in the first form, making a list of it if it is a lambda or not a
   list already. If there are more forms, inserts the first form as the
   second item in second form, etc.&amp;quot;
   {:added &amp;quot;1.0&amp;quot;}
   &amp;#91;x &amp;amp; forms&amp;#93;
   &amp;#40;loop &amp;#91;x x, forms forms&amp;#93;
     &amp;#40;if forms
       &amp;#40;let &amp;#91;form &amp;#40;first forms&amp;#41;
-            threaded &amp;#40;if &amp;#40;seq? form&amp;#41;
+            threaded &amp;#40;if &amp;#40;and &amp;#40;seq? form&amp;#41; &amp;#40;not &amp;#40;#{'fn 'fn&amp;#42;} &amp;#40;first form&amp;#41;&amp;#41;&amp;#41;&amp;#41;
                        &amp;#40;with-meta `&amp;#40;&amp;#126;&amp;#40;first form&amp;#41; &amp;#126;x &amp;#126;@&amp;#40;next form&amp;#41;&amp;#41; &amp;#40;meta form&amp;#41;&amp;#41;
                        &amp;#40;list form x&amp;#41;&amp;#41;&amp;#93;
         &amp;#40;recur threaded &amp;#40;next forms&amp;#41;&amp;#41;&amp;#41;
       x&amp;#41;&amp;#41;&amp;#41;
 
 &amp;#40;defmacro -&amp;gt;&amp;gt;
-  &amp;quot;Threads the expr through the forms. Inserts x as the
-  last item in the first form, making a list of it if it is not a
+  &amp;quot;Threads the expr through the forms. Inserts x as the last item
+  in the first form, making a list of it if it is a lambda or not a
   list already. If there are more forms, inserts the first form as the
   last item in second form, etc.&amp;quot;
   {:added &amp;quot;1.1&amp;quot;}
   &amp;#91;x &amp;amp; forms&amp;#93;
   &amp;#40;loop &amp;#91;x x, forms forms&amp;#93;
     &amp;#40;if forms
       &amp;#40;let &amp;#91;form &amp;#40;first forms&amp;#41;
-            threaded &amp;#40;if &amp;#40;seq? form&amp;#41;
+            threaded &amp;#40;if &amp;#40;and &amp;#40;seq? form&amp;#41; &amp;#40;not &amp;#40;#{'fn 'fn&amp;#42;} &amp;#40;first form&amp;#41;&amp;#41;&amp;#41;&amp;#41;
               &amp;#40;with-meta `&amp;#40;&amp;#126;&amp;#40;first form&amp;#41; &amp;#126;@&amp;#40;next form&amp;#41;  &amp;#126;x&amp;#41; &amp;#40;meta form&amp;#41;&amp;#41;
               &amp;#40;list form x&amp;#41;&amp;#41;&amp;#93;
         &amp;#40;recur threaded &amp;#40;next forms&amp;#41;&amp;#41;&amp;#41;
       x&amp;#41;&amp;#41;&amp;#41;
 
 &amp;#40;def map&amp;#41;
 
 &amp;#40;defn &amp;#94;:private check-valid-options
diff --git a/test/clojure/test&amp;#95;clojure/macros.clj b/test/clojure/test&amp;#95;clojure/macros.clj
index ce17bb38..9fb1fa9e 100644
--- a/test/clojure/test&amp;#95;clojure/macros.clj
+++ b/test/clojure/test&amp;#95;clojure/macros.clj
@@ -106,8 +106,20 @@
   &amp;#40;is &amp;#40;nil? &amp;#40;loop &amp;#91;&amp;#93;
               &amp;#40;as-&amp;gt; 0 x
                 &amp;#40;when-not &amp;#40;zero? x&amp;#41;
                   &amp;#40;recur&amp;#41;&amp;#41;&amp;#41;&amp;#41;&amp;#41;&amp;#41;
   &amp;#40;is &amp;#40;nil? &amp;#40;loop &amp;#91;x nil&amp;#93; &amp;#40;some-&amp;gt; x recur&amp;#41;&amp;#41;&amp;#41;&amp;#41;
   &amp;#40;is &amp;#40;nil? &amp;#40;loop &amp;#91;x nil&amp;#93; &amp;#40;some-&amp;gt;&amp;gt; x recur&amp;#41;&amp;#41;&amp;#41;&amp;#41;
   &amp;#40;is &amp;#40;= 0 &amp;#40;loop &amp;#91;x 0&amp;#93; &amp;#40;cond-&amp;gt; x false recur&amp;#41;&amp;#41;&amp;#41;&amp;#41;
   &amp;#40;is &amp;#40;= 0 &amp;#40;loop &amp;#91;x 0&amp;#93; &amp;#40;cond-&amp;gt;&amp;gt; x false recur&amp;#41;&amp;#41;&amp;#41;&amp;#41;&amp;#41;
+
+&amp;#40;deftest -&amp;gt;lambda-test
+  &amp;#40;is &amp;#40;= 'a &amp;#40;-&amp;gt; 'a &amp;#40;&amp;#40;fn &amp;#91;x&amp;#93; x&amp;#41;&amp;#41;&amp;#41;&amp;#41;&amp;#41;
+  &amp;#40;is &amp;#40;= 'a &amp;#40;-&amp;gt; 'a &amp;#40;fn &amp;#91;x&amp;#93; x&amp;#41;&amp;#41;&amp;#41;&amp;#41;
+  &amp;#40;is &amp;#40;= 'a &amp;#40;-&amp;gt; 'a #&amp;#40;identity %&amp;#41;&amp;#41;&amp;#41;&amp;#41;
+  &amp;#40;is &amp;#40;= 'a &amp;#40;-&amp;gt; 'a &amp;#40;#&amp;#40;identity %&amp;#41;&amp;#41;&amp;#41;&amp;#41;&amp;#41;&amp;#41;
+
+&amp;#40;deftest -&amp;gt;&amp;gt;lambda-test
+  &amp;#40;is &amp;#40;= 'a &amp;#40;-&amp;gt;&amp;gt; 'a &amp;#40;&amp;#40;fn &amp;#91;x&amp;#93; x&amp;#41;&amp;#41;&amp;#41;&amp;#41;&amp;#41;
+  &amp;#40;is &amp;#40;= 'a &amp;#40;-&amp;gt;&amp;gt; 'a &amp;#40;fn &amp;#91;x&amp;#93; x&amp;#41;&amp;#41;&amp;#41;&amp;#41;
+  &amp;#40;is &amp;#40;= 'a &amp;#40;-&amp;gt;&amp;gt; 'a #&amp;#40;identity %&amp;#41;&amp;#41;&amp;#41;&amp;#41;
+  &amp;#40;is &amp;#40;= 'a &amp;#40;-&amp;gt;&amp;gt; 'a &amp;#40;#&amp;#40;identity %&amp;#41;&amp;#41;&amp;#41;&amp;#41;&amp;#41;&amp;#41;
-- 
2.21.0 &amp;#40;Apple Git-122.2&amp;#41;
&lt;/code&gt;&lt;/pre&gt;
</description>
<enclosure>

</enclosure>
<pubDate>
Tue, 14 Jan 2020 00:00:00 -0800
</pubDate>
</item>
<item>
<guid>
http://code.thosmos.com/posts/2020-01-04-spec-driven-db.html
</guid>
<link>
http://code.thosmos.com/posts/2020-01-04-spec-driven-db.html
</link>
<title>
Spec-Driven DB
</title>
<description>
 &lt;p&gt;Someone asked on &lt;a href='https://ask.clojure.org'&gt;ask.clojure.org&lt;/a&gt; about modeling SQL data in Clojure, so &lt;a href='https://ask.clojure.org/index.php/8484/how-do-you-approach-data-database-modeling-in-clojure?show=8988#a8988'&gt;I answered the following&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;I recently moved an app from a 13 year old java/hibernate/MySQL design to Clojure/Datomic&lt;/p&gt;&lt;p&gt;I wrote a library that reads the MySQL table schema, creates an abstract table spec, then uses that spec to create the Datomic schema and migrates all the data over to Datomic. You're welcome to check it out for inspiration (I attempted to write it somewhat generally, but it's fairly tightly focused on my use case) &lt;a href='https://github.com/thosmos/mysql-to-datomic'&gt;thosmos/mysql-to-datomic&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The main point however is that I created my own abstract data spec to describe the tables, columns, and foreign keys, such that I had everything I needed to not only generate the Datomic schema, but also later auto-generated GraphQL and EQL APIs and front-end CRUD data entry forms with linked subforms and data validations, all from this abstract spec. I've attempted to pull the essence of this model-defining spec into a minimal library here: &lt;a href='https://github.com/thosmos/domain-spec'&gt;thosmos/domain-spec&lt;/a&gt;&lt;/p&gt;&lt;p&gt;It again tightly serves my use case, but perhaps it will inspire you to realize that in Clojure you can do your own thing quite easily and powerfully without over-relying on libraries and dependencies.&lt;/p&gt;
</description>
<enclosure>

</enclosure>
<pubDate>
Sat, 04 Jan 2020 00:00:00 -0800
</pubDate>
</item>
<item>
<guid>
http://code.thosmos.com/posts/2019-12-04-spec-driven-ui.html
</guid>
<link>
http://code.thosmos.com/posts/2019-12-04-spec-driven-ui.html
</link>
<title>
Spec-Driven UI
</title>
<description>
&lt;p&gt;Background: I'm embarking on a long overdue revamp of an old environmental data management system I made 12 years ago that's used by local watershed science organizations to manage their science data.  Ever since I built the first version, I've been thinking about how to improve it, but life and other projects have kept me preoccupied, and it's mainly a volunteer effort.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;It has a normalized MySQL DB with a &lt;a href='https://en.wikipedia.org/wiki/Apache_Flex'&gt;Flex&lt;/a&gt; frontend that mutates a tree of relational data objects created by &lt;a href='https://hibernate.org/'&gt;Hibernate&lt;/a&gt; and sent across the wire via &lt;a href='https://github.com/graniteds/graniteds'&gt;GraniteDS&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;A few years ago when I saw &lt;a href='https://youtu.be/BNkYYYyfF48'&gt;Paul deGrandis' Data-Driven talk&lt;/a&gt; I realized Clojure would be a good fit for a rewrite.  Even more years ago, I considered using XML, XML Schema, and XForms.  With XForms 2.0 recently released, I can't say that would be a bad way to go... Declarative UI for the win, but &quot;XML is messy Lisp!&quot; and why not just use the most useful real modern Lisp -&gt; Clojure?&lt;/p&gt;&lt;p&gt;The intention is to migrate the database to &lt;a href='https://www.datomic.com/'&gt;Datomic&lt;/a&gt; and keep the same basic normalized table schema with a &lt;a href='https://en.wikipedia.org/wiki/Single-page_application'&gt;SPA web frontend&lt;/a&gt; that reads and transacts a tree of relational data across the wire.  &lt;a href='https://clojure.org/'&gt;Clojure&lt;/a&gt;(&lt;a href='https://clojurescript.org/'&gt;script&lt;/a&gt;), Datomic, &lt;a href='https://github.com/edn-format/edn'&gt;EDN&lt;/a&gt;, and &lt;a href='https://edn-query-language.org/'&gt;EQL&lt;/a&gt; are perfect for this.  Datomic's pull query and tree-like transaction format makes it easy to move a whole tree of relational entities both ways across the wire relatively painlessly.  MySQL + Hibernate + GraniteDS were amazing for this 12 years ago, but I like the Datomic + EQL approach more now, mainly because it's a more pure data + code approach.  Clojure is great because it's the most simple and stable language I'm aware of, the same language can be used for both client and server, and EDN/&lt;a href='https://github.com/cognitect/transit-format'&gt;Transit&lt;/a&gt; is a desirable data format for the wire when talking to a browser.&lt;/p&gt;&lt;p&gt;Progress: I wrote a library that migrated the schema and data over to Datomic from MySQL (&lt;a href='https://github.com/thosmos/mysql-to-datomic'&gt;thosmos/mysql-to-datomic&lt;/a&gt;).  This maps tables to namespaces, and columns to attributes in that namespace.  One thing I needed was a higher level notion of foreign-keys from one entity type to another, which Datomic doesn't have, as well as other SQLisms like string length for VarChar columns, etc.  So I created a simple domain spec that describes this (&lt;a href='https://github.com/thosmos/domain-spec'&gt;thosmos/domain-spec&lt;/a&gt;), which is then used for generating the Datomic schema, &lt;a href='https://github.com/walmartlabs/lacinia'&gt;Lacinia&lt;/a&gt; GraphQL schema, and can contain DB- or GraphQL-specific things, etc.  I'm just using Datomic, so I haven't bothered with other DBs. &lt;/p&gt;&lt;p&gt;This GraphQL backend is already live on our 1st draft production frontend at &lt;a href='https://riverdb.org'&gt;RiverDB.org&lt;/a&gt; and our &lt;a href='http://riverdb.surge.sh/'&gt;dev frontend&lt;/a&gt;.  The specs are used to generate the GraphQL endpoints for all of the tables using only one resolver.&lt;/p&gt;&lt;p&gt;Here's an example of one domain entity from the domain spec:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;edn&quot;&gt;{:db/id &amp;quot;toxtest&amp;quot;,
 :entity/name &amp;quot;toxtest&amp;quot;,
 :entity/ns :entity.ns/toxtest,
 :entity/attrs
   &amp;#91;{:attr/name &amp;quot;ComplianceCode&amp;quot;,
     :attr/key :toxtest/ComplianceCode,
     :attr/position 8,
     :attr/cardinality :one,
     :attr/type :ref,
     :attr/ref {:entity/ns :entity.ns/compliancelevellookup},
     :attr/strlen 5}
    {:attr/name &amp;quot;LabSampleID&amp;quot;,
     :attr/key :toxtest/LabSampleID,
     :attr/position 4,
     :attr/cardinality :one,
     :attr/type :string,
     :attr/strlen 20}&amp;#93;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Goals: &lt;/p&gt;&lt;p&gt;1) Generate a basic CRUD UI from the domain specs such that the domain data can be easily edited.  Generating the UI from the spec enables using the same UI app for multiple different schema shapes, or to more easily migrate the schema without having to touch the UI app.  In other words: a spec-driven UI.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I currently have a dev &lt;a href='https://marmelab.com/react-admin/'&gt;marmelab/react-admin&lt;/a&gt; CRUD UI running that's generated from the spec and that provides a good default editing experience for each individual &quot;table&quot; or entity type.  The next step is to create some custom UIs that combine a graph of related entity types into a single form.  This is where I'm wishing I could be doing this in CLJS instead.&lt;/p&gt;&lt;p&gt;1.5) It would be possible to have some simple schema migration tooling that would provide functions for doing the most common migrations (add an attribute, add an entity type, alias a key, add but not change a join reference, etc) and then would change both the spec and the live DB schema.&lt;/p&gt;&lt;p&gt;2) Because the spec is just data and is itself defined using its own spec format, it's possible to use the same spec-driven CRUD UI to edit it using the same means as the domain data editor.   This will be a &quot;schema editor&quot; that enables the user to: add an attribute to an entity type; change an attribute's validation function; add a new entity type; add a new entity reference attribute to an existing entity type, etc.  These types of changes result in schema migrations under the hood, using the same tooling as described in (1.5) above.  This approach enables adding new fields, and aliasing existing fields, but not renaming or removing fields, since this data might be referenced from elsewhere in the distributed system that is the internet.  Also, since we're dealing with historic environmental data, we want to never lose anything, but only track changes and modifications.&lt;br /&gt;&lt;/p&gt;&lt;p&gt; This self-editing of the schema is accomplished by using the same spec-driven UI CRUD editor because the schema specs are self-defined using the same spec attrs as domain specs (very meta):&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;edn&quot;&gt;&amp;#91;{:entity/ns    :entity.ns/entity,
  :entity/name  &amp;quot;Entity&amp;quot;
  :entity/pks   &amp;#91;:entity/ns&amp;#93;
  :entity/doc   &amp;quot;The entity spec for the entity spec -&amp;gt; so meta&amp;quot;
  :entity/attrs &amp;#91;{:attr/key         :entity/ns,
                  :attr/type        :keyword,
                  :attr/cardinality :one,
                  :attr/identity   true,
                  :attr/doc         &amp;quot;unique keyword for this spec like -&amp;gt; :entity.ns/sitevisit&amp;quot;}
                 {:attr/key         :entity/name,
                  :attr/type        :string,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;A display name&amp;quot;}
                 {:attr/key         :entity/doc,
                  :attr/type        :string,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;documentation about this entity&amp;quot;}
                 {:attr/key         :entity/prnFn,
                  :attr/type        :string,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;a function with the entity as its arg for printing this entity&amp;quot;}
                 {:attr/key         :entity/summaryKeys,
                  :attr/type        :keyword,
                  :attr/cardinality :many,
                  :attr/doc         &amp;quot;a subset of this entity's attrs to display in a summary list&amp;quot;}
                 {:attr/key         :entity/pks,
                  :attr/type        :keyword,
                  :attr/cardinality :many,
                  :attr/doc         &amp;quot;list of attribute keywords that collectively act as a unique constraint for this entity&amp;quot;}
                 {:attr/key         :entity/attrs,
                  :attr/type        :ref,
                  :attr/ref         {:entity/ns :entity.ns/attr}
                  :attr/cardinality :many,
                  :attr/component  true,
                  :attr/doc         &amp;quot;attribute specs for this entity&amp;quot;}&amp;#93;}
 {:entity/ns    :entity.ns/attr,
  :entity/name  &amp;quot;Attribute&amp;quot;
  :entity/pks   &amp;#91;:attr/key&amp;#93;
  :entity/doc   &amp;quot;The entity spec for the attribute spec -&amp;gt; very meta&amp;quot;
  :entity/attrs &amp;#91;{:attr/key         :attr/key,
                  :attr/type        :keyword,
                  :attr/cardinality :one,
                  :attr/identity   true,
                  :attr/doc         &amp;quot;the datomic attribute keyword name -&amp;gt; :&amp;lt;entity-ns&amp;gt;/&amp;lt;attr-key&amp;gt; -&amp;gt; :sitevisit/SiteVisitDate&amp;quot;}
                 {:attr/key         :attr/type,
                  :attr/type        :keyword,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;#{:keyword :string :boolean :long :bigint :float :double :bigdec :ref :instant :uuid :uri :bytes}&amp;quot;}
                 {:attr/key         :attr/cardinality,
                  :attr/type        :keyword,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;#{:one :many}&amp;quot;}
                 {:attr/key         :attr/name,
                  :attr/type        :string,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;a display name&amp;quot;}
                 {:attr/key         :attr/ref,
                  :attr/type        :ref,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;a DB ref to the entity spec for the target type of this ref attribute, i.e. Foreign Key&amp;quot;}
                 {:attr/key         :attr/identity,
                  :attr/type        :boolean,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;is this an identity attribute?&amp;quot;}
                 {:attr/key         :attr/unique,
                  :attr/type        :boolean,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;is this a unique attribute?&amp;quot;}
                 {:attr/key         :attr/primary,
                  :attr/type        :boolean,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;is this a primary key?&amp;quot;}
                 {:attr/key         :attr/required,
                  :attr/type        :boolean,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;is this attribute required?&amp;quot;}
                 {:attr/key         :attr/component,
                  :attr/type        :boolean,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;is this a component attribute?&amp;quot;}
                 {:attr/key         :attr/noHistory,
                  :attr/type        :boolean,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;skip keeping history in datomic?&amp;quot;}
                 {:attr/key         :attr/fulltext,
                  :attr/type        :boolean,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;index full text?&amp;quot;}
                 {:attr/key         :attr/derived,
                  :attr/type        :boolean,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;is this attribute a derived value?&amp;quot;}
                 {:attr/key         :attr/deriveFn,
                  :attr/type        :string,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;fn code for deriving this attr value&amp;quot;}
                 {:attr/key         :attr/deriveAttrs,
                  :attr/type        :keyword,
                  :attr/cardinality :many,
                  :attr/doc         &amp;quot;attrs of the parent entity that are used to derive this attr value&amp;quot;}
                 {:attr/key         :attr/doc,
                  :attr/type        :string,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;this attribute's doc string&amp;quot;}
                 {:attr/key         :attr/decimals,
                  :attr/type        :long,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;number of decimals in this floating point value&amp;quot;}
                 {:attr/key         :attr/strlen,
                  :attr/type        :long,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;number of chars in this string value&amp;quot;}
                 {:attr/key         :attr/position,
                  :attr/type        :long,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;ordinal position - optional for visual ordering&amp;quot;}
                 {:attr/key         :attr/nextAutoVal,
                  :attr/type        :long,
                  :attr/cardinality :one,
                  :attr/noHistory   true,
                  :attr/doc         &amp;quot;next auto-increment value. optional&amp;quot;}
                 {:attr/key         :attr/gql,
                  :attr/type        :string,
                  :attr/cardinality :one,
                  :attr/doc         &amp;quot;A GraphQL-friendly attribute name&amp;quot;}&amp;#93;}&amp;#93;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;3) An obvious further meta meta option would be to enable editing the spec's specs!  This would for example enable adding a new field to the Attr spec, which would cause it to show up in the schema editor for all schema attributes.  This is probably too meta to even mention, but it's possible using the same spec-driven UI!&lt;/p&gt;
</description>
<enclosure>

</enclosure>
<pubDate>
Wed, 04 Dec 2019 00:00:00 -0800
</pubDate>
</item>
<item>
<guid>
http://code.thosmos.com/posts/2018-05-06-realworld-vase.html
</guid>
<link>
http://code.thosmos.com/posts/2018-05-06-realworld-vase.html
</link>
<title>
Realworld Clojure in a Vase on a Pedestal
</title>
<description>
&lt;p&gt;&lt;img src=&quot;/img/realworld.png&quot; alt=&quot;image 1&quot; /&gt;&lt;/p&gt;&lt;p&gt;In this exceedingly complex &quot;modern&quot; and ever increasingly fast paced world of internet technological development, it's amazing to see an effort like the &lt;a href='https://realworld.io'&gt;RealWorld Example Apps&lt;/a&gt;, &quot;an Exemplary fullstack Medium.com clone,&quot; offer a path of unity and coherence in the midst of the chaos of so many options. It's a thorough front- and back-end API spec for a non-trivial demo app that many different people have built both front- and back-ends for, including re-frame, Keechma, React, Elm, Vue, Scala, Rails, Node, Django, Go, and many more.&lt;/p&gt;&lt;p&gt;Currently there are a couple of Clojurescript frontends, but no complete Clojure backend.  I've never built anything with Paul de Grandis' &lt;a href='https://github.com/cognitect-labs/vase'&gt;Vase&lt;/a&gt;, but I've admired its data-driven architecture for declaratively building APIs fast. I'm curious how well it would do at building a Real World API backend. There's only one way to find out ...&lt;/p&gt;&lt;p&gt;The First step is to create a new Vase app:&lt;pre&gt;&lt;code&gt;lein new vase realworld-vase
 &lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;This creates a basic ready-to-run Vase app:&lt;pre&gt;&lt;code&gt;realworld-vase
├── Capstanfile
├── Dockerfile
├── README.md
├── boot.properties
├── build.boot
├── config
│   └── logback.xml
├── project.clj
├── resources
│   └── realworld-vase&amp;#95;service.edn
├── src
│   └── realworld&amp;#95;vase
│       ├── server.clj
│       └── service.clj
└── test
    └── realworld&amp;#95;vase
        ├── service&amp;#95;test.clj
        └── test&amp;#95;helper.clj

6 directories, 12 files
 &lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Most of the magic happens in the EDN config file: &lt;code&gt;resources/realworld-vase&amp;#95;service.edn&lt;/code&gt;&lt;/p&gt;&lt;p&gt;By default, the app has a few example API endpoints which we can see after running the app:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;lein run
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we now browse to &lt;a href='http://localhost:8080/api/realworld-vase/v1/db'&gt;http://localhost:8080/api/realworld-vase/v1/db&lt;/a&gt; we'll see a list of all of the installed attributes in the sample Datomic database.&lt;/p&gt;&lt;p&gt;Our goal is to define a set of attributes to cover all of the necessary fields in the &lt;a href='https://github.com/gothinkster/realworld/tree/master/api'&gt;RealWorld API description&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The first entity type is the User:&lt;pre&gt;&lt;code class=&quot;json&quot;&gt;{
  &amp;quot;user&amp;quot;: {
    &amp;quot;email&amp;quot;: &amp;quot;jake@jake.jake&amp;quot;,
    &amp;quot;token&amp;quot;: &amp;quot;jwt.token.here&amp;quot;,
    &amp;quot;username&amp;quot;: &amp;quot;jake&amp;quot;,
    &amp;quot;bio&amp;quot;: &amp;quot;I work at statefarm&amp;quot;,
    &amp;quot;image&amp;quot;: null
  }
}
 &lt;/code&gt;&lt;/pre&gt; We can define this in the &lt;code&gt;resources/realworld-vase&amp;#95;service.edn&lt;/code&gt; file by replacing the example user schema with the following:&lt;pre&gt;&lt;code class=&quot;edn&quot;&gt;:realworld-vase/user-schema
{:vase.norm/requires &amp;#91;:realworld-vase/base-schema&amp;#93;
 :vase.norm/txes &amp;#91;#vase/schema-tx
   &amp;#91;&amp;#91;:user/username :one :string :identity &amp;quot;A user's unique identifier&amp;quot;&amp;#93;
    &amp;#91;:user/email :one :string :unique &amp;quot;A user's email&amp;quot;&amp;#93;
    &amp;#91;:user/bio :one :string :fulltext &amp;quot;A short blurb about a user&amp;quot;&amp;#93;
    &amp;#91;:user/company :one :ref &amp;quot;A user's employer&amp;quot;&amp;#93;
    &amp;#91;:user/image :one :uri &amp;quot;URL of a user's photo&amp;quot;&amp;#93;
    &amp;#91;:user/token :one :string :index &amp;quot;A user's auth token&amp;quot;&amp;#93;&amp;#93;&amp;#93;}
 &lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Vase idempotently applies DB schema using conformity, so we'll need to restart the server in order to see our new attributes.&lt;pre&gt;&lt;code&gt;lein run
 &lt;/code&gt;&lt;/pre&gt; Now we should see our new attributes in the &lt;code&gt;db&lt;/code&gt; endpoint &lt;a href='http://localhost:8080/api/realworld-vase/v1/db'&gt;http://localhost:8080/api/realworld-vase/v1/db&lt;/a&gt;. (Search for &lt;code&gt;user/username&lt;/code&gt; and &lt;code&gt;user/email&lt;/code&gt; for example.)&lt;/p&gt;&lt;p&gt;Further down in our &lt;code&gt;realworld-vase&amp;#95;service.edn&lt;/code&gt; file, we can change the definition for the &lt;code&gt;/users&lt;/code&gt; endpoint to the following:&lt;pre&gt;&lt;code class=&quot;edn&quot;&gt; &amp;quot;/users/:username&amp;quot; {:get #vase/query
    {:name :realworld-vase.v1/user-id-page
     :params &amp;#91;username&amp;#93;
     :edn-coerce &amp;#91;username&amp;#93;
     :query &amp;#91;:find ?e
             :in $ ?username
             :where
             &amp;#91;?e :user/username ?username&amp;#93;&amp;#93;}}

 &amp;quot;/user&amp;quot; {:get #vase/query {:name :realworld-vase.v1/user-page
                            ;; All params are required to perform the query
                            :params &amp;#91;email&amp;#93;
                            :query &amp;#91;:find ?e
                                    :in $ ?email
                                    :where
                                    &amp;#91;?e :user/email ?email&amp;#93;&amp;#93;}
          :post #vase/transact {:name :realworld-vase.v1/user-create
                                ;; `:properties` are pulled from the parameters
                                :properties &amp;#91;:db/id
                                             :user/username
                                             :user/email
                                             :user/bio&amp;#93;}
          :delete #vase/transact {:name :realworld-vase.v1/user-delete
                                  :db-op :vase/retract-entity
                                  ;; :vase/retract-entity requires :db/id to be supplied
                                  :properties &amp;#91;:db/id&amp;#93;}}
 &lt;/code&gt;&lt;/pre&gt; We should now be able to transact and query some users via the API.&lt;pre&gt;&lt;code&gt;curl -H &amp;quot;Accept: application/json&amp;quot; -X POST -d '{&amp;quot;payload&amp;quot;: &amp;#91;{&amp;quot;user/username&amp;quot;:&amp;quot;thosmos&amp;quot;,&amp;quot;user/email&amp;quot;:&amp;quot;thos37@gmail.com&amp;quot;,&amp;quot;user/bio&amp;quot;:&amp;quot;coding the thosmos&amp;quot;}&amp;#93;}' http://localhost:8080/api/realworld-vase/v1/user
 &lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;To be continued ...&lt;/p&gt;
</description>
<enclosure>

</enclosure>
<pubDate>
Sun, 06 May 2018 00:00:00 -0700
</pubDate>
</item>
<item>
<guid>
http://code.thosmos.com/posts/2017-04-02-boot-clj-startup.html
</guid>
<link>
http://code.thosmos.com/posts/2017-04-02-boot-clj-startup.html
</link>
<title>
Boot-clj Startup
</title>
<description>
&lt;p&gt;After having a great conversation with &lt;a href='https://twitter.com/mkaplinskiy'&gt;Mike Kaplisky&lt;/a&gt; at ClojureWest 2017 about how to optimize a Clojure build chain to be as fast as possible (they use &lt;a href='https://buckbuild.com/'&gt;Buck&lt;/a&gt; at &lt;a href='https://www.ladderlife.com/'&gt;Ladder&lt;/a&gt;), I was inspired to look at &lt;a href='http://boot-clj.com/'&gt;Boot-clj&lt;/a&gt;, my preferred build tool, with some fresh and curious eyes.  I'd like to understand better how Boot works under the hood, so I figure a good way to start is to time some various pieces of it in comparison with lein, clojure, and the JVM.&lt;/p&gt;&lt;p&gt;To start with, let's create a hello world boot-built app:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;boot -d boot/new new -t app -n hello
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;By default, after loading deps with an initial run, it takes about 16 sec to build a jar.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;time boot build

Compiling 1/1 hello.core...
Writing pom.xml and pom.properties...
Adding uberjar entries...
Writing hello-0.1.0-SNAPSHOT-standalone.jar...
Writing target dir&amp;#40;s&amp;#41;...

36.62s user 5.61s system 267% cpu 15.780 total
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let's add a super basic boot task to &lt;code&gt;build.boot&lt;/code&gt; that does nothing:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&amp;#40;deftask noop
  &amp;quot;the simplest boot task&amp;quot;
  &amp;#91;&amp;#93;
  identity&amp;#41;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;time boot noop

17.88s user 0.83s system 380% cpu 4.920 total
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It takes 18 sec cpu time, 5 sec real time, just to do nothing!  At least it's using all my 4 cores.&lt;/p&gt;&lt;p&gt;Let's compare this with a hello world java app:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;// Hello.java
public class Hello {
    public static void main&amp;#40;String&amp;#91;&amp;#93; args&amp;#41;{
        System.out.println&amp;#40;&amp;quot;Hello world&amp;quot;&amp;#41;;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;javac Hello.java

time java Hello

0.12s user 0.04s system 103% cpu 0.149 total
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;0.15 secs!  That's amazing!  Now let's compare that with running our Clojure hello world:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;time java -jar target/hello-0.1.0-SNAPSHOT-standalone.jar

2.57s user 0.16s system 196% cpu 1.395 total
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;1.4 secs ... There's a big time difference there from the java hello world, but it's still much less than running an empty boot task. What causes a bare boot strap to take so long?&lt;/p&gt;
</description>
<enclosure>

</enclosure>
<pubDate>
Sun, 02 Apr 2017 00:00:00 -0700
</pubDate>
</item>
<item>
<guid>
http://code.thosmos.com/posts/2015-09-08-data-driven.html
</guid>
<link>
http://code.thosmos.com/posts/2015-09-08-data-driven.html
</link>
<title>
Data Driven
</title>
<description>
&lt;p&gt;It's funny to look back on my previous post from years ago.  It was written literally a day or two before I watched a talk by Paul de Grandis called, &lt;a href='https://www.youtube.com/watch?v=BNkYYYyfF48'&gt;Unlocking Data-Driven Systems&lt;/a&gt;, in which he described a system closer to what I'd imagined than anything I've seen.  It inspired me to go much further with Clojure. In fact, I've spent the past year and a half dedicated to learning and working in Clojure, even building my current project with it, &lt;a href='https://take2.org'&gt;Take2.org&lt;/a&gt;.  Though I have yet to re-tackle the original project that inspired my previous post, the possibility still exists, and the inspiration returns semi-regularly.&lt;/p&gt;&lt;p&gt;  UPDATE 2017-04-01: I just experienced my first &lt;a href='http://2017.clojurewest.org/'&gt;ClojureWest&lt;/a&gt; and I met Paul de Grandis and a bunch of other amazing Clojurists.   It was very inspiring and I'm impressed with how welcoming and friendly the community is.  I'm now planning to work on the   aforementioned science data management project starting after Summer Solstice, so it really seems like forces are aligning   for this to happen.  At ClojureWest I learned a ton of approaches and solutions that are relevant, so I'm excited to apply   what I've learned.&lt;/p&gt;
</description>
<enclosure>

</enclosure>
<pubDate>
Tue, 08 Sep 2015 00:00:00 -0700
</pubDate>
</item>
<item>
<guid>
http://code.thosmos.com/posts/2014-12-15-imagining-atomatizing-the-app.html
</guid>
<link>
http://code.thosmos.com/posts/2014-12-15-imagining-atomatizing-the-app.html
</link>
<title>
Imagining atomatizing the App
</title>
<description>
&lt;p&gt;This morning, while reflecting on a late night of working through &lt;a href='https://swannodette.github.io'&gt;David Nolen&lt;/a&gt;'s (&lt;a href='https://github.com/swannodette'&gt;swannodette&lt;/a&gt;) Intro to Clojurescript and &lt;a href='https://github.com/swannodette/om'&gt;Om&lt;/a&gt; &lt;a href='https://github.com/swannodette/om/wiki/Basic-Tutorial'&gt;Basic Tutorial&lt;/a&gt;, I had an epiphany, an insight into a solution to a problem I've been working on for about 15 years.  The goal I've been seeking is an elegant app for a non-programmer user to create a custom, elegant scientific data collection and visualization app.  It requires building up a data survey from simple and complex data types, possibly based on an existing denormalized database schema, and linking that with an easily customizable data entry screen.  It's kind of like Access, but more complex while also easier to use.  Yes, a paradox.  &lt;a href='https://en.wikipedia.org/wiki/XRX_%28web_application_architecture%29'&gt;XRX&lt;/a&gt; is a major step in the right direction, but the designed by commitee feel and actually writing and reading XML and XQuery leaves something to be desired.  However, I've never really given it a chance and it could be great.  I like the document store approach of eXistDB, similar to MongoDB for JSON data.  &lt;a href='https://opendatakit.org/'&gt;ODK&lt;/a&gt; is doing amazing things with XRX, but only by reverting to HTML and javascript for the UI.&lt;/p&gt;&lt;p&gt;I've taken a few runs at the solution over the years, starting with a naive PHP app in the foggy beginning of my programming career, and a couple of paid database gigs for clients for similar needs, but I have yet to attain the degree of Nirvana I know is possible.  When I became familiar with Clojure, I intuited that it would probably be much more useful for the job, due to its homoiconic nature, being represented in its own data format and amenable to meta-programming, and to its immutable data types - a severely useful toolbox.  But the language has been opaque to me, and simultaneously both too complex and too simple to see how to use it to its fullest ... until this morning.  Suddenly, while looking through my bay windows to the trees behind my monitor, I saw the architecture I needed to use.  Kind of a mix between a spreadsheet tree, data schema UML, Pure Data wiring, a Swift playground, etc, but that changes based on position within the multidimensional data abstraction context tree.&lt;/p&gt;&lt;p&gt;One possible step toward making this app easier to contemplate is the definition of the app itself, which Om's component-based nature aids.  However, I'm wondering if there's an additional step of abstraction that could be taken to a simpler declarative definition of the app, which would be easier for a user or a builder app to construct and edit.  For example, here's a prototypical Om component definition:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    &amp;#40;defn comment &amp;#91;{:keys &amp;#91;author text&amp;#93;} owner&amp;#93;
      &amp;#40;om/component
        &amp;#40;dom/div #js {:className &amp;quot;comment&amp;quot;}
          &amp;#40;dom/h2 nil author&amp;#41;
          &amp;#40;dom/span nil text&amp;#41;&amp;#41;&amp;#41;&amp;#41;
&lt;/code&gt;&lt;/pre&gt;&lt;a href='https://gist.github.com/fredyr/8460923'&gt;https://gist.github.com/fredyr/8460923&lt;/a&gt;&lt;p&gt;It's a very nice declarative way to define a component, and reminds me of Enyo's nested declarative javascript component model:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;{kind: &amp;quot;onyx.Button&amp;quot;, name:&amp;quot;Image Button&amp;quot;, ontap:&amp;quot;buttonTapped&amp;quot;, components: &amp;#91;
  {tag: &amp;quot;img&amp;quot;, attributes: {src: &amp;quot;assets/enyo-logo-small.png&amp;quot;}},
  {content: &amp;quot;There is an image here&amp;quot;}
&amp;#93;}
&lt;/code&gt;&lt;/pre&gt;&lt;a href='https://github.com/enyojs/onyx/blob/master/samples/ButtonSample.js'&gt;https://github.com/enyojs/onyx/blob/master/samples/ButtonSample.js&lt;/a&gt;&lt;p&gt;Enyo is the closest tool I've found yet to enabling the workflow I need.  However, it feels funky.  I know, I'm picky.&lt;/p&gt;&lt;p&gt;Clojure's Lispiness is very amenable to representing the tag nature of XML and HTML, and is preferrable if the UI is being generated programmatically anyway.  In that vein, Enyo's definition is more clear in some ways because it is simpler, relying on a convention or schema for being converted into running code.  But what if the Om approach were to be similarly abstracted further?  Can the following simpler version work?&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;{ :name :comment
  :class &amp;quot;comment&amp;quot;
  ;:kind :div ; :div is the default
  :content &amp;#91;
   { :kind :h2, :state :author}
   { :kind :span, :state :text}&amp;#93;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It's easier for me to read and seems to contain all of the same essential info, without a lot of the repetitive code (&lt;a href='https://en.wikipedia.org/wiki/Don%27t_repeat_yourself'&gt;DRY&lt;/a&gt;).  This declaration is taking advantage of some conventions.  One is that a component will pass to its children the same state that it received, unless otherwise stated (pun intended).  It's unnecesary to declare its input variables, and it only defines more refined sub-cursors when handing state to its children.  This declaration could be used to generate the CLJS code above.  This component uses no state of its own; it's just a container DIV.  This is another convention: a component is by default a DIV, unless otherwise noted.  Here's another more complex component, first in Om code:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&amp;#40;defn comment-list &amp;#91;cs owner&amp;#93;
  &amp;#40;om/component
    &amp;#40;dom/div nil
      &amp;#40;dom/div #js {:className &amp;quot;commentList&amp;quot;}
        ;; Helper function build-all builds a vector of components
        &amp;#40;om/build-all comment cs&amp;#41;&amp;#41;
      &amp;#40;dom/button #js
        {:onClick #&amp;#40;change-author cs &amp;quot;Fredrik&amp;quot;&amp;#41;}
        &amp;quot;Change authors&amp;quot;&amp;#41;&amp;#41;&amp;#41;&amp;#41;

&lt;/code&gt;&lt;/pre&gt;from: &lt;a href='https://gist.github.com/fredyr/8460923'&gt;https://gist.github.com/fredyr/8460923&lt;/a&gt;&lt;p&gt;and here's a mapped abstraction:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;{ :name :commentList
  :state &amp;#91;:comment&amp;#93; ; Declares that this component accepts a vector of :comment components.
  :content &amp;#91;
    { :class &amp;quot;commentList&amp;quot;
      :content &amp;#91;
        {:kind :comment, :build :all}&amp;#93;}
    { :kind :button
      :onClick &amp;#91;:changeAuthor :state &amp;quot;Frederik&amp;quot;&amp;#93;
      :content &amp;quot;Change authors&amp;quot;}&amp;#93;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The mapping of the &quot;build-all&quot; macro seems a bit wonky, but I'm confident there's some reasonable way to represent it.  Also, does this need a schema?  A Schema might be nice, but really, it's all convention over configuration, a la Enyo, yes?  Hmmm ...&lt;/p&gt;&lt;p&gt;&lt;a href='https://gist.github.com/thos37/2d3dae5ce298f8a952b8'&gt;Here's a full mapping with its original&lt;/a&gt;&lt;/p&gt;&lt;p&gt;My impression is that the mapped form would be much easier for me to reason around with the aim of building an app that could read and write this structure.  These structures would be the blueprint from which to actually output the clojure code above.  It's the equivalent of the relationship between the data in the atom and its runtime representation to the user.&lt;/p&gt;&lt;p&gt;Plus, as if that weren't enough, there's a huge bonus to this approach: undo and change branching (and saving, and sharing) of the app itself, FOR FREE!  Non-programmers are overwhelmed enough trying to make a relatively sophisticated app, but this would make it much easier to save different versions, try something for a while, save it, go back a few steps, go in a different direction, save it, and then be able to browse around through the different versions.  This might even make it possible to more easily diff different versions.&lt;/p&gt;&lt;p&gt;One caveat to this approach is that functions will need to be saved and versioned outside of the the app-def atom.  Or they can be represented as strings and edited from within the builder app.  I neglected to mention that I'm fairly new to clojure, only having worked through David Nolen's intro tutorial yesterday, so I have much to learn and discover of the Joys of Clojure.&lt;/p&gt;
</description>
<enclosure>

</enclosure>
<pubDate>
Mon, 15 Dec 2014 00:00:00 -0800
</pubDate>
</item>
<item>
<guid>
http://code.thosmos.com/posts/2013-05-01-geometric-algebra-with-clojure-1.html
</guid>
<link>
http://code.thosmos.com/posts/2013-05-01-geometric-algebra-with-clojure-1.html
</link>
<title>
Geometric Algebra with Clojure - Part 1
</title>
<description>
&lt;p&gt;I've been exploring Geometric Algebra (GA) and Clojure for a while, and I'm finding some potential to combine my learning of both. Here are my first steps on a Mac: &lt;ol&gt;  	&lt;li&gt;Download and install GaiGen2.5 (http://sourceforge.net/projects/g25/) which is a GA code generator for a variety of languages, including java.&lt;/li&gt;  	&lt;li&gt;Generate some sample algebra specs, generate the code from the sample Conformal 3d Java spec file, compile, and package into a jar.  I get a warning, &quot;Warning: No operator bindings are possible for output language Java.&quot;  I wonder if Gaigen would benefit from being rewritten in Clojure, to gain from its metaprogramming capabilities ...&lt;/li&gt;         &lt;/p&gt;&lt;pre&gt;&lt;code&gt;cd &amp;#126;/Develop/GA/gaigen25/
g25&amp;#95;test&amp;#95;generator -sa .
cd TestG25
g25 c3ga&amp;#95;java/c3ga&amp;#95;java.xml
javac c3ga&amp;#95;pkg/&amp;#42;.java
jar cvf c3ga.jar c3ga&amp;#95;pkg
&lt;/code&gt;&lt;/pre&gt; 	&lt;li&gt;Create a new clojure project, add the GA jar as a resource to the project.clj, and start a repl:&lt;/li&gt; 	&lt;pre&gt;&lt;code&gt;cd ..
lein new gaclj
cd gaclj
mkdir lib
cp ../TestG25/c3ga.jar lib
nano project.clj

&amp;#40;defproject gaclj &amp;quot;0.1.0-SNAPSHOT&amp;quot;
  :description &amp;quot;First try at doing geometric algebra in clojure&amp;quot;
  :url &amp;quot;https://www.thosmos.com/?p=256&amp;quot;
  :license {:name &amp;quot;Eclipse Public License&amp;quot;
            :url &amp;quot;http://www.eclipse.org/legal/epl-v10.html&amp;quot;}
  :resource-paths &amp;#91;&amp;quot;lib/c3ga.jar&amp;quot;&amp;#93;
  :dependencies &amp;#91;&amp;#91;org.clojure/clojure &amp;quot;1.4.0&amp;quot;&amp;#93;&amp;#93;&amp;#41;
    &lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;lein repl
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;user=&amp;gt; &amp;#40;def mv &amp;#40;c3ga&amp;#95;pkg.mv.&amp;#41;&amp;#41;
#'user/mv

user=&amp;gt; &amp;#40;.set mv 25.0&amp;#41;
nil

user=&amp;gt;; mv
#&amp;lt;mv 25.00&amp;gt;

user=&amp;gt; &amp;#40;.toString mv&amp;#41;
&amp;quot;25.00&amp;quot;

user=&amp;gt; &amp;#40;def e1 &amp;#40;c3ga&amp;#95;pkg.c3ga/vectorE1&amp;#41;&amp;#41;
#'user/e1

user=&amp;gt;; e1
#&amp;lt;vectorE3GA 1.00&amp;#42;e1&amp;gt;

user=&amp;gt; &amp;#40;def e2 &amp;#40;c3ga&amp;#95;pkg.c3ga/vectorE2&amp;#41;&amp;#41;
#'user/e2

user=&amp;gt; e2
#&amp;lt;vectorE3GA 1.00&amp;#42;e2&amp;gt;

user=&amp;gt; &amp;#40;def e3 &amp;#40;c3ga&amp;#95;pkg.c3ga/vectorE3&amp;#41;&amp;#41;
#'user/e3

user=&amp;gt; &amp;#40;c3ga&amp;#95;pkg.c3ga/add e1 e2&amp;#41;
#&amp;lt;vectorE3GA 1.00&amp;#42;e1 + 1.00&amp;#42;e2&amp;gt;

user=&amp;gt; &amp;#40;def e12 &amp;#40;c3ga&amp;#95;pkg.c3ga/add e1 e2&amp;#41;&amp;#41;
#'user/e12

user=&amp;gt; e12
#&amp;lt;vectorE3GA 1.00&amp;#42;e1 + 1.00&amp;#42;e2&amp;gt;

user=&amp;gt; &amp;#40;.toString e12&amp;#41;
&amp;quot;1.00&amp;#42;e1 + 1.00&amp;#42;e2&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This looks promising. Some next steps will be to get the objects drawn on a canvas of some kind, and then to get some live updating going on, ideally in a &lt;a href=&quot;http://www.lighttable.com&quot; target=&quot;&lt;i&gt;blank&quot;&gt;LightTable&lt;/a&gt; and &lt;a href=&quot;http://worrydream.com/&quot; target=&quot;&lt;/i&gt;blank&quot;&gt;Bret Victor&lt;/a&gt; style. I've also been exploring &lt;a href=&quot;http://sourceforge.net/projects/tealsim&quot; target=&quot;_blank&quot;&gt;TEALsim&lt;/a&gt;, used by MIT for their EM simulations. So another goal is to get the GA working with an EM simulator...&lt;/p&gt;
</description>
<enclosure>

</enclosure>
<pubDate>
Wed, 01 May 2013 00:00:00 -0700
</pubDate>
</item>
</channel>
</rss>
