XT16 - Kris Jenkins: Adventures in User Interfaces

'JavaScript is falling down'. This is the Ukuele tune that Kris Jenkins serenades us with at XT16. JavaScript was great for websites of old, but it is becoming increasingly inadequate for the current generation of thick client apps that we are building today.

Kris states that there's a new wave of languages here to give us hope. These languages bring us better architectures and fresh ways of thinking; that we have an optimistic future ahead of us.

I really enjoyed Kris's talk; in particular a live Elm coding demo where he highlights how joyful it can be to have a simple yet elegant type system on hand to deliver great validation of code and data as well as error messages.

Enjoy.

Permalink

Reagent deep dive part 3: Sequences



(ns my.reagent-examples
(:require
[clojure.string :as string]
[reagent.core :as reagent]
[reagent.ratom]))

(enable-console-print!)
Welcome to the third leg of the Reagent deep dive tour.

In part 2 we got into the thick of the component lifecycle. Today we move on to nuances surrounding the representation of sequences. This will be quite a change of pace as it is a somewhat less tangible topic. We'll need to use our imaginations a little.




Sequences

Seven. Apparently this is the minimum number of times a person has to try to do something before said person actually succeeds in doing it. -- Rusty Bentley


In part 1 it was noted that [[:div] [:div]] is not a valid Reagent component. However [:div [[:div] [:div]]] is a valid component, and has a special meaning. Reagent forms do allow a sequence as a child of a tag. A sequence is interpreted as a React array, which is interpreted to mean a collection of elements which may get swapped around.

So we can write a component as:

Example U: A sequence of circles


[:svg {:width 200 :height 200}
(for [i (range 30)]
[:circle
{:r (* (inc i) 5)
:cx 100
:cy 100
:fill "none"
:stroke (str "rgb(0, " (* i 10) "," (* (- 30 i) 10) ")")}])]

Instead of using into like we have been thus far:
(into [:svg] (for ...))

Note that the former results in something like:
[:svg [[:circle] [:circle] ...]]

While the later results in something like:
[:svg [:circle] [:circle] ...]

What difference does it make? Not much that we can notice at first glance. We'll only notice a difference if we open the developer console. Example U causes React to print warnings in the developer console:
Warning: Every element in a seq should have a unique :key

What the heck is React complaining about?

Well, imagine for a moment that you had written the following list:
  • Princess torte.
  • Black forest gateau.
  • Apple pie.



And then you realized that ice cream should be in the list, at the very top. The logical thing to do would be to insert ice cream above everything else. But another way to get the final list would be to replace princess torte with ice cream, then replace black forest gateau with princess torte, replace apple pie with black forest gateau, and finally add apple pie at the very end. The reason that we chose the first, more logical and faster method was because we knew that we wanted to insert a new element.

Imagine for a moment that you emailed me the initial list and I put it into a spreadsheet. Then you sent me the final list. I could probably figure out to insert ice cream at the top is the most efficient change. So I make the update. But what if you emailed me a list of about 100 things, and then later emailed me the same list but with 20 items inserted, moved, deleted, or changed? It would be really hard for me to figure out the minimal updates required to update my spreadsheet. So instead I would copy the entire list over the top of my spreadsheet.

There is however another solution! When you sent me the list you could have assigned each logical item an id number. That way when I got the second list, I could quickly identify the minimal updates required. I could walk through the new list, looking only at the id number. If the number was in the existing list and at the same position I could check that the item contents haven't changed and then move on. If the existing list had the id number at a different position I could move it to the correct position. If the existing list didn't have the id number, I would know to insert a new row. This sounds a little tedious, but I hope it is clear that there is a mechanical process available that which would ultimately result in less change to the spreadsheet.

This minimal update scenario applies to HTML elements. React's job is to figure out the minimal changes to make to a HTML page in order to transition from the existing view state to the desired view state. If it can swap HTML elements around, that is far fewer updates than recreating them in different positions. You can give React the hint it needs by passing a unique key per element. To specify a key on an element in a sequence, use the mysterious ^{:key k}

Tip: The item key is represented in metadata attached to the item. ^ is shorthand to set the metadata of an object. You can also pass :key as an attribute of a hiccup form.

Here is how we represent a sequence of keyed entities:

Example V: A sequence of sub-components, with identity keys


(def favorites
(reagent/atom
{"d632" {:name "Princess torte."
:order 2}
"1ae2" {:name "Black forest gateau."
:order 3}
"5117" {:name "Apple pie."
:order 4}
"42ae" {:name "Ice cream."
:order 1}}))

(defn list-by [entities sort-k]
[:ul
(for [[k v] (sort-by (comp sort-k val) @entities)]
^{:key k}
[:li (:name v)])])

(defn favorites-by-order-and-name []
[:div
[:h3 "By order"]
[list-by favorites :order]
[:h3 "By name"]
[list-by favorites :name]])

The idea in this example is that each item has a unique ID, perhaps assigned by a database, generated when the item was created. That unique ID is used as the key in the sequence.

This example is clearly contrived! These components aren't big enough or numerous enough for us to waste our precious brainpower worrying about their rendering performance. For small lists of small components, you wont notice any performance difference between the three options for representing them; as direct children of a parent element, as a keyless sequence of elements, or as a keyed sequence of elements. However this tiny example does allow us to discuss exactly what those 3 alternatives look like, and why in the broader picture we should care.

  1. We could have used into to make all the list items direct children of the unordered list. This would have resulted in no warnings and not required the key. Updating the list with new data would result in some unnecessary DOM updates.
  2. We could have left off the ^{:key k} and ignored the warnings in the developer console. Updating the list with new data would result in some unnecessary DOM updates.
  3. As presented there was a natural key available, so we annotated the each list item with metadata. There are no warnings in the console and updating the list will result in fewer DOM updates.

The pattern of "I have a bunch of entities I need to render" pops up here and there in practice. That is why the distinction between expressing sequences exists. By way of illustration I shall describe one such scenario. In my Napkindo app I display a gallery of drawings. Each drawing is an entity that has a database assigned id, and various information attached to it such as the drawing title, the line paths in the drawing, and the owner. For very large collections of large elements, assigning React keys improves UI performance. And it turns out that many of the large collections of large elements we run into fit this pattern nicely.

There is another scenario where entity identity should be preserved; animating transitions of elements. Generally we don't care which elements in our DOM contain what HTML because it all looks the same once the updates are applied. But when rendering transitions, it becomes obvious which elements are linked to which logical entities. Visual identity must follow logical identity. I'll let you ponder that.




In this highly technical diagram each box is logically bound to its contents. Keys provide the mechanism to make this binding.

Coming back to our options... now that we have pondered at length the 3 ways of expressing sequences we can happily choose whichever we prefer, realizing that it wont make any difference in most circumstances. My personal opinion is that warnings are best heeded, so I avoid keyless sequences. My rule of thumb is to key my sequences if there is a natural key available. If there is no natural key, I default to using into the parent tag instead. I think it best to avoid the temptation to make up a sequential key by assigning each item in the sequence an index number. Doing so complicates the code to avoid a warning by deceiving React about the identity semantics of the sequence. The semantic of a key is that it identifies a unique entity in the sequence. In short, if there is a natural key, use it. If there is no natural key, put the items into the parent tag as children.

There is one final consideration when using sequences; lazy deref is not allowed.

Example W: A button that does not work due to lazy deref


(def message (reagent/atom "Everything is fine"))

(defn bad []
[:div
[:button
{:on-click
(fn [e]
(reset! message "Oh no, oh dear, oh my."))}
"Panic!"]
(for [i (range 3)]
[:h3 @message])])
This example does not work! It will produce a warning:
Warning: Reactive deref not supported in lazy seq, it should be wrapped in doall
From Reagent's perspective calling bad does not deref message. Rendering [:h3 @message] occurs later but at that point Reagent no longer knows that the parent component is bad. Because Reagent doesn't evaluate the lazy sequence immediately it is unaware that badshould respond to changes in message.



We can force evaluation of a lazy sequence that derefs by wrapping it in a doall, or by using using vec or into to realize the sequence, and then it will work just fine.

Exercise: Pressing the panic button does nothing. Fix example V by forcing evaluation of the lazy sequence, and press the panic button.

Fortunately this somewhat confusing circumstance of deref inside a lazy sequence occurs rarely, and produces a warning with the advice on how to remedy it. Notice that we don't need to force a lazy sequence that consumes a deref, which is far more common. For example (for [x @xs] ...) does not need to be forced because the deref is not inside the lazy sequence.

An intuition for sequence performance

The proof is in the pudding. -- Unknown


I made some pretty bold claims about the impact of keys and haven't provided a guide for exactly when performance starts to be impacted aside from some vague notion of "large". It is not a simple thing to quantify and will of course be situational, but we can gain a bit of intuition here of what a "large" sequence is. Let's play out our earlier thought experiment about a list of tasty desserts getting updated.

Example X: A large keyed sequence of delectable disposition


(def words
["ice" "cream" "chocolate" "pastry" "pudding" "raspberry" "mousse"
"vanilla" "wafer" "waffle" "cake" "torte" "gateau" "pie" "cookie"
"cupcake" "mini" "hot" "caramel" "meringue" "lemon" "marzipan" "mocha"
"strawberry" "tart" "custard" "fruit" "baklava" "jelly" "banana" "coconut"])

(defn rand-name []
(string/capitalize (string/join " " (take (+ 2 (rand-int 5)) (shuffle words)))))

(def desserts (reagent/atom ()))

(defn make-a-dessert [e]
(swap! desserts conj {:id (random-uuid)
:name (rand-name)}))

(defn make-many-desserts [e]
(dotimes [i 100]
(make-a-dessert nil)))

(defn color-for [x]
(str "#" (.toString (bit-and (hash x) 0xFFFFFF) 16)))

(defn dessert-item [{:keys [id name]}]
[:li
[:svg {:width 50 :height 50}
[:circle
{:r 20 :cx 25 :cy 25 :fill (color-for id)}]
[:rect {:x 15 :y 15 :width 20 :height 20 :fill (color-for name)}]]
[:span [:em [:strong name]]]])

(defn desserts-list []
[:ol
(for [dessert @desserts]
^{:key (:id dessert)}
[dessert-item dessert])])

(defn dessertinator []
[:div
[:button {:on-click make-a-dessert} "Invent a new dessert"]
[:button {:on-click make-many-desserts} "Invent 100 new desserts"]
[desserts-list]])

Exercise: desserts-list currently keys each dessert-item. Invent 2000 desserts by pressing the "100" button 20 times. Then add another single dessert. Creating desserts should be fairly fast. Next delete the ^{:key (:id dessert)} line in desserts-listand perform the same steps. At about 2000 desserts, it takes noticeably longer to create new desserts!

Tip: Every time you change the code, the desserts list is reset, so you might want to make another change to the code so that you can finish the article when you are done experimenting.

As you can see, computers are amazing and it really does take a very large sequence before performance is impacted by the lack of a key. With the keyed approach we can preserve performance with many, many items in our sequence.


Conclusion

A gene is a long sequence of coded letters, like computer information. Modern biology is becoming very much a branch of information technology. -- Richard Dawkins




Phew! We made it to our third stop off.

We observed 3 different ways to express a sequence of elements and discussed how React treats them. In the 4th leg of the tour we shall not be encountering any new concepts. Instead we will be applying some of the concepts we have already encountered to build out a mini sketching application.

I hope to see you again soon for part 4, where we'll handle some more practical UI challenges.

Permalink

Reagent deep dive part 2: The lifecycle of a component



(ns my.reagent-examples
(:require
[reagent.core :as reagent]
[reagent.ratom]))

(enable-console-print!)

Welcome to the second leg of the Reagent deep dive tour!

In part 1 we saw how to create components and react to change. Now we move on to some more challenging aspects of UI building. Today we examine how to represent component local state and how to access the rendered DOM nodes. We will need these capabilities in order to create some more interesting components and make use of third party JavaScript libraries so that we can render a 3D scene.




Component forms

One of the basic things about a string is that it can vibrate in many different shapes or forms, which gives music its beauty. -- Edward Witten


We have a mechanism for change, which we examined in part 1, and it works great for everything we can define in Reagent that has access to an external reagent/atom. But not everything falls into this neat view of the world. There are two exceptions:
  1. What if we want a self-contained component with it's own state? We want to be able to define and retain a local reagent/atom instead of relying on one from the surrounding environment in order to build reusable components.
  2. What if we want a component to call JavaScript functions on to the actual HTML elements after they are rendered? There are many great JavaScript libraries that operate directly on HTML elements, and in order to use them we need to be able to invoke them after the component has created the elements.
The Reagent answer comes in two additional forms of specifying what a component is. So far we have been using the first form, a function that returns hiccup. In total there are 3 important forms for specifying components:
  1. A function that returns a hiccup vector.
  2. A function that returns a function.
  3. A function that returns a Class.


Moodswingerscale


We saw plenty of examples of form 1 in part 1 of the deep dive tour. All the examples were functions that returned hiccup. So let's examine form 2 more closely now.


Example K: Reagent component form 2 - A function that returns a function


(defn greetings []
(fn []
[:h3 "Hello world"]))

Here is a function that returns a function. The returned function (the inner function) returns a hiccup vector representing HTML. The outer function just returns the inner function.

Exercise: Is a function that returns a function that returns a function a valid Reagent component? Find out by modifying the examples above. Wrap the inner function in yet another function.

Form 2 is useful for performing initial setup for a component. A common usage of this form is to establish some local state. Consider this example which creates a reagent/atom counter per instance:

Example L: Reagent component form 2 - A function that returns a function


(defn a-better-mouse-trap [mouse]
(let [mice (reagent/atom 1)]
(fn render-mouse-trap [mouse]
(into
[:div
[:button
{:on-click
(fn [e]
(swap! mice (fn [m] (inc (mod m 4)))))}
"Catch!"]]
(repeat @mice mouse)))))

[:div
[a-better-mouse-trap
[:img
{:src "https://www.domyownpestcontrol.com/images/content/mouse.jpg"
:style {:width "150px" :border "1px solid"}}]]
[a-better-mouse-trap
[:img
{:src "https://avatars1.githubusercontent.com/u/9254615?v=3&s=150"
:style {:border "1px solid"}}]]]

These mice traps each have their own count of mice per trap. Compare this example to the previous counter in part 1 example H, which relied on a single global count. Global state, and state passed as arguments tend to be useful for application features. Local state tends to be useful for self contained components.

Notice that this example is really just a closure (variable capture) occurring inside a function.

Seeing that this is a common pattern, Reagent also provides with-let which will take care of the inner function for you:

Example M: Using with-let to avoid returning a function


(defn lambda [rotation x y]
[:g {:transform (str "translate(" x "," y ")"
"rotate(" rotation ") ")}
[:circle {:r 50, :fill "green"}]
[:circle {:r 25, :fill "blue"}]
[:path {:stroke-width 12
:stroke "white"
:fill "none"
:d "M -45,-35 C 25,-35 -25,35 45,35 M 0,0 -45,45"}]])

(defn spinnable []
(reagent/with-let [rotation (reagent/atom 0)]
[:svg
{:width 150 :height 150
:on-mouse-move
(fn [e]
(swap! rotation + 30))}
[lambda @rotation 75 75]]))

(defn several-spinnables []
[:div
[:h3 "Move your mouse over me"]
[a-better-mouse-trap [spinnable]]])


This is a slightly more compact way of expressing the same concept. The rotation atom is created only once, while the component will be re-rendered when the rotation value is modified.


O.K. so what about form 3? Let's look at how to create a Class:

Example N: Reagent component form 3 - A function that returns a Class


(defn announcement []
(reagent/create-class
{:reagent-render
(fn []
[:h3 "I for one welcome our new insect overlords."])}))





This code should look familiar in that the reagent-render function is exactly like any other component function we have seen before. It has been wrapped explicitly in a create-class call. The only difference is that we can also specify other lifecycle functions, which we will make use of soon. 

A React Class lifecycle consists of:

Mounting (Occurs once when the component is created)

  • constructor
  • componentWillMount
  • render
  • componentDidMount

Updating (Occurs many times as the component reacts to change)

  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

Unmounting (Occurs once when the component will be removed from the DOM)

  • componentWillUnmount
You can read more about the component lifecycle in the React docs.

Fortunately we can take a much simpler view of the world in Reagent! The two lifecycle functions that can be of additional use to us are the componentDidMount function, which will allow us to interact with the created DOM elements, and the componentWillUnmount which will allow us to do cleanup.

Before we go much further into what create-class allows us to do, let's take a brief interlude to examine a case where it looks like we need to use a class, but in fact we can avoid using one.

Example O: Performing cleanup


(defn mouse-position []
(reagent/with-let [pointer (reagent/atom nil)
handler (fn [e]
(swap! pointer assoc
:x (.-pageX e)
:y (.-pageY e)))
_ (js/document.addEventListener "mousemove" handler)]
[:div "Pointer moved to: " (str @pointer)]
(finally
(js/document.removeEventListener "mousemove" handler))))

The finally clause of with-let will run when mouse-pos is no longer tracked anywhere, in this case when tracked-pos is unmounted. The same thing could be achieved with a Class that specified a component-will-unmount.

Reagent has well thought out facilities that allow us to write our components as simple functions that respond to change. Knowing the model of how those function relate to the underlying React lifecycle is useful for reasoning about component behaviors and being able to choose concise functions as much as possible. The bottom of the abstraction is creating the Class directly. Why do we still need the ability to create a Class?





Well... one case is that when we need to access the DOM node of the component we constructed. This comes up when making use of non-React JavaScript UI libraries. For instance if you want to use Google Charts; you need to call a render function on a target element after it is created. This is where the the component-did-mount lifecycle method becomes valuable.

Tip: You can alternatively provide a ref function as an attribute to a hiccup form to access DOM nodes. The ref function will be called with the DOM element on every render. This is less generally useful so we'll focus on using the class lifecycle.

Let's see how to make use of form 3 by creating a ThreeJS canvas.

Example P: Reagent component form 3 - Creating a ThreeJS canvas


(defn create-renderer [element]
(doto (js/THREE.WebGLRenderer. #js {:canvas element :antialias true})
(.setPixelRatio js/window.devicePixelRatio)))

(defn three-canvas [attributes camera scene tick]
(let [requested-animation (atom nil)]
(reagent/create-class
{:display-name "three-canvas"
:reagent-render
(fn three-canvas-render []
[:canvas attributes])
:component-did-mount
(fn three-canvas-did-mount [this]
(let [e (reagent/dom-node this)
r (create-renderer e)]
((fn animate []
(tick)
(.render r scene camera)
(reset! requested-animation (js/window.requestAnimationFrame animate))))))
:component-will-unmount
(fn [this]
(js/window.cancelAnimationFrame @requested-animation))})))

This is a more involved example to show the use of a non-React JavaScript UI library. We are using the ThreeJS library to render a scene. The important thing to look for in this example code is the use of lifecycle methods; reagent-render is a component function that returns hiccup HTML, component-did-mount is called when the element is mounted into the page, and component-will-unmount is called just before the element leaves the page.

There are 2 interop tasks we do in our ThreeJS component:
  1. We start a request animation frame loop to render the scene. But we are careful to stop the animation loop when the component is unmounted. This will allow our component to play nicely with our page if we add and remove it.
  2. We create a renderer that targets the DOM node after it is mounted into the page.
Ok great, but where's our scene? We need to construct some lights and objects to see anything interesting. Let's make a 3D version of the concentric circles we made in SVG earlier.

Example Q: A ThreeJS version of concentric circles


(defn create-scene []
(doto (js/THREE.Scene.)
(.add (js/THREE.AmbientLight. 0x888888))
(.add (doto (js/THREE.DirectionalLight. 0xffff88 0.5)
(-> (.-position) (.set -600 300 600))))
(.add (js/THREE.AxisHelper. 50))))

(defn mesh [geometry color]
(js/THREE.SceneUtils.createMultiMaterialObject.
geometry
#js [(js/THREE.MeshBasicMaterial. #js {:color color :wireframe true})
(js/THREE.MeshLambertMaterial. #js {:color color})]))

(defn fly-around-z-axis [camera scene]
(let [t (* (js/Date.now) 0.0002)]
(doto camera
(-> (.-position) (.set (* 100 (js/Math.cos t)) (* 100 (js/Math.sin t)) 100))
(.lookAt (.-position scene)))))

(defn v3 [x y z]
(js/THREE.Vector3. x y z))

(defn lambda-3d []
(let [camera (js/THREE.PerspectiveCamera. 45 1 1 2000)
curve (js/THREE.CubicBezierCurve3.
(v3 -30 -30 10)
(v3 0 -30 10)
(v3 0 30 10)
(v3 30 30 10))
path-geometry (js/THREE.TubeGeometry. curve 20 4 8 false)
scene (doto (create-scene)
(.add
(doto (mesh (js/THREE.CylinderGeometry. 40 40 5 24) "green")
(-> (.-rotation) (.set (/ js/Math.PI 2) 0 0))))
(.add
(doto (mesh (js/THREE.CylinderGeometry. 20 20 10 24) "blue")
(-> (.-rotation) (.set (/ js/Math.PI 2) 0 0))))
(.add (mesh path-geometry "white")))
tick (fn []
(fly-around-z-axis camera scene))]
[three-canvas {:width 150 :height 150} camera scene tick]))

Tada! We have a 3D scene.


Exercise: Add some more meshes to the scene. Complete the Lambda symbol (λ) by adding a diagonal down mesh.

What I find really neat is that this 3D scene composes well with our existing components, here it is inside the mouse trap:

Example R: Composing 3D concentric circles with a counter


[:div
[a-better-mouse-trap [lambda-3d]]
[a-better-mouse-trap [spinnable]]]

With attention to the component lifecycle we were able to make use a library that was not designed with React or Reagent in mind. We didn't need a complicated wrapper; creating a class was the easy bit. Most of our effort was specifying the scene itself.

Seeing as we created a 3D scene, let's make use of it to draw something else. A Sierpinski 3D gasket is a recursively defined object with volume that approaches zero each step, while the surface area remains constant. That's pretty weird huh?

Example S: Sierpinski Gasket in 3D


(def pyramid-points
[[-0.5 -0.5 0 "#63B132"] [-0.5 0.5 0 "#5881D8"] [0.5 0.5 0 "#90B4FE"] [0.5 -0.5 0 "#91DC47"] [0 0 1 "white"]])

(defn add-pyramid [scene x y z size color]
(.add scene
(doto
(let [g (js/THREE.Geometry.)]
(set! (.-vertices g)
(clj->js (for [[i j k] pyramid-points]
(v3 i j k))))
(set! (.-faces g)
(clj->js (for [[i j k] [[0 1 2] [0 2 3] [1 0 4] [2 1 4] [3 2 4] [0 3 4]]]
(js/THREE.Face3. i j k))))
(mesh g color))
(-> (.-position) (.set x y z))
(-> (.-scale) (.set size size size)))))

(defn add-pyramids [scene x y z size color]
(if (< size 4)
(add-pyramid scene x y z (* size 1.75) color)
(doseq [[i j k color] pyramid-points]
(add-pyramids scene
(+ x (* i size))
(+ y (* j size))
(+ z (* k size))
(/ size 2)
color))))

(defn gasket-3d []
(let [camera (js/THREE.PerspectiveCamera. 45 1 1 2000)
scene (doto (create-scene)
(add-pyramids 0 0 0 32 "white"))
tick (fn [] (fly-around-z-axis camera scene))]
[three-canvas {:width 640 :height 640} camera scene tick]))

Suggested soundtrack for appreciating the Sierpinski gasket:





Exercise: Can you make a tetrahedral gasket by modifying the points and faces list? (Hint: you just need to delete one of the base points to make a triangular prism.) How about a cubic gasket?

ClojureScript really shines in it's facilities for avoiding repetitive boilerplate.


Lifecycle Review

Twice and thrice over, as they say, good is it to repeat and review what is good. -- Plato




Most Reagent components can be expressed as a function, especially if they rely on state being passed to them as an argument. Some components will create local state, access the DOM node, or need to do some setup/teardown. All components have a lifecycle. They get created, mounted into the DOM, rendered, and unmounted from the DOM. A component potentially calls render many times as it's inputs change. It remains in the DOM until unmounted.

In order to show the lifecycle in action, let's log what's happening in a form 2 component (a function that returns a function).

(def messages (reagent/atom []))

(defn log [& args]
(apply cljs.core/println args)
(swap! messages
(fn [xs]
(doall (take 10 (cons (apply str (.toLocaleTimeString (js/Date.)) "| " args) xs))))))

(defn with-log [component]
[:div
component
(into
[:ul]
(for [line @messages]
[:li line]))])

Example T: Observing the lifecycle of a puppy


(defn puppy [x]
(log "puppy created, x:" x)
(let [mouse-over? (reagent/atom false)]
(fn [y]
(log "puppy rendered, x:" x " y:" y " mouse-over?:" @mouse-over?)
[:span {:on-mouse-over (fn [e] (reset! mouse-over? true))
:on-mouse-out (fn [e] (reset! mouse-over? false))}
[:img {:src "https://goo.gl/fMzXOU"
:style {:width "150px",
:border "1px solid",
:transform (str "scale(" (if @mouse-over? 1.1 1) ")")}}]])))

(defn lifecycle-review []
(reagent/with-let [x (reagent/atom "1")]
[:div
[:label "Type in a value for x: "
[:input {:on-change (fn [e] (reset! x (.. e -target -value)))}]]
[with-log [a-better-mouse-trap [puppy @x]]]]))

Pop quiz: Enter a string in the text box above and mouse over the puppy. You should see that x and y do not match. Why are they different? Now click "catch" to create a new puppy. See that x now has the new value when you mouse over the new puppy, but x still has the old value when you mouse over the old puppy. Can you explain why?

As you can see by playing with this example, puppy is called once at creation, but the function it returns is called whenever you mouse over the puppy. One trap to avoid is forgetting to specify the inner function arguments, or giving them a different name. I intentionally gave them different names in the above example to demonstrate that x is being captured from the outer function. The captured value won't change! However this is easily avoided if you keep the inner function arguments identical to the outer arguments. If the arguments are identical, the inner function will not capture any of the outer bindings.


Conclusion

The pain of parting is nothing to the joy of meeting again. -- Charles Dickens


We have reached the second stop of our deep dive tour.

At this point we have covered the principal syntax and features of Reagent. We observed a variety of UI challenges and the forms Reagent provides to address them. Reagent's fundamental abstraction is a view component. A function that returns HTML as hiccup is a component. A function that returns a function is a component. A function that returns a Class is a component. These three forms allow us to manage lifecycle concerns such as state and DOM node interaction.

Editing code in the browser itself is a great way to try out Reagent. If you want to build some larger ideas you might find KLIPSE useful. If you enjoy interactive tutorials, make sure you check out the excellent articles in the KLIPSE blog.

In part 3 of our tour we will examine the nuances of dealing with sequences of subcomponents. I hope you can join me again for that soon!

Permalink

The REPL

The REPL

Clojure pills, knowing your tools, spandex
View this email in your browser

The REPL

-main

Libraries & Books.

  • aws-arn: parse AWS ARNs in Clojure
  • Max Penet dons some spandex to query Elasticsearch
  • net: the Clojure netty companion
  • dom-top from Aphyr (SFW)

People are worried about Types. ?

Foundations.

Tools.

Learning.

Misc.

I really, really enjoyed this discussion on the design and implementation of OK Log, a log management service.

Copyright © 2017 Daniel Compton, All rights reserved.


Want to change how you receive these emails?
You can update your preferences or unsubscribe from this list

Email Marketing Powered by MailChimp

Permalink

Seancorfield/boot-new Has Moved to Boot/new

I’m pleased to announce that the “Boot new” task formerly known as seancorfield/boot-new has moved to the Boot organization, as boot-clj/boot-new and that the group/artifact ID is now boot/new.

You can use this to easily create a new Boot-based project:

boot -d boot/new new -t app -n my-new-boot-app

Permalink

Software Developer at SOS Capital, Inc (Full-time)

We are looking to grow our team with the addition of a talented Software Developer.

We’re on a mission to develop software that can transform lending and help millions of small businesses. We're more interested in finding the right person, and helping establish the right role for you here, than a specific job task list. That said,

You'll need:

  • Experience or an interest in learning Functional Programming: Clojure(script), underscore/lodash, point free JS

  • A minimum of 3 years of professional experience in HTML5, SCSS, and JavaScript (ES6)

  • Excellent problem solving and critical thinking skills

  • Equal willingness to both learn and to teach

  • Portfolio of work (open source, commercial, personal) you can demonstrate

  • Familiarity or experience working with React.js

  • A computer science degree, a related degree, or relevant life experience

You'll be happiest here if:

  • you're creative

  • you have an interest in Finance, analytics, optimizations, and discovering gems in mountains of data

  • you like to take ownership of projects and bring them to life

Open to Contract or Full-Time

About SOS Capital

S.O.S. Capital is a family owned and oriented business. S.O.S. Capital was started to provide a vital service to the business community – the kind of quick capital investment that banks just can’t match. We aim to help small businesses grow by making the process of acquiring funds easy and painless. My dream is to one day be the best and cheapest provider of capital in this industry.

Our Team

Our team includes seasoned finance and tech industry professionals with backgrounds in fields as diverse as real estate, insurance, and investment.

Required education: Bachelor's

Required experience:

Software Development: 2 years

Javascript: 3 years CSS: 1 year

Job Type: Full-time

Job Location:

New York City, NY

Principals Only. Please, no recruiters.

Get information on how to apply for this position.

Permalink

Knowing Your Tools

This article is excerpted from chapter 1 of the “Clojure Standard Library, An Annotated reference”, the Manning book I’m currently working on.

Book Cover

; TLDR

The post shows you why it’s important to dedicate time to learn the content of the Clojure standard library. The standard library contains loads of interesting functions and knowing them often leads to a better functional design. An example is given to show how a simple program can be improved by learning what you have available.

The book is available from Manning website along with a few sample chapters. Readers of this blog can get a 50% discount when using the code mlborgatti !

Tools

Software development is often compared to a craft, despite the fact that it’s predominantly an intellectual activity. While software development is abstract in nature there are many craft-oriented aspects to it:

  • The keyboard requires time and dedication to operate correctly. There are endless discussions on the best keyboard layout for programmers, for example to speed up typing (Dvorak users often claim huge benefits compared to QWERTY users. Here’s one comparison, including other kind of layouts: http://lifehacker.com/should-i-use-an-alternative-keyboard-layout-like-dvorak-1447772004).
  • The development environment is a key aspect of programmers productivity and another source of debate (almost reaching a religious connotation). Mastering a development environment often translates into learning useful key combinations and ways to customize the most common operations.
  • Libraries, tools and idioms surrounding the language. Almost everything above the pure syntax rules.
  • Proficiency in several programming languages is definitely a plus in the job marketplace and the way to achieve it is by practicing them on a regular basis including getting familiar with APIs and libraries the language offers.
  • Many other aspects require specific skills depending on the area of application: teaching, presenting or leadership.

The focus on mastering programming skills is so important that it became one of the key objectives of the Software Craftsmanship Movement. Software Craftsmanship advocates learning through practice and promotes an apprenticeship process similar to other professions.

The standard library is definitely one of the most important tools to master a language. One aspect that characterizes the standard library is the fact that it is already packaged with a language when you first experiment with it. Interestingly, it doesn’t get the amount of attention you would expect for such an easy to reach tool.

Why should I care about the Standard Library?

The expressiveness of a language is often described as the speed at which ideas can be translated into working software. Part of the expressiveness comes from the language itself in terms of syntax, but another fundamental part comes from the standard library which is usually provided out of the box. A good standard library liberates the programmer from the most mundane tasks like connecting to data sources, parsing XML, dealing with numbers and a lot more. When the standard library does a good job, developers are free to concentrate on core business aspects of an application, boosting productivity and return of investment.

Consider also that a deep knowledge of the standard library is often what distinguish an average developer from the expert. The expert can solve problems more elegantly and faster than the beginner because, apart from having solved the same problem before, they can compose a complex solution by pulling small pieces together from the standard library

Finally, the standard library contains solutions to common programming problems that have been battle-tested over generations of previous applications. It is certainly the case for Clojure. The robustness and reliability that comes with that kind of stress is difficult to achieve otherwise. There will be possibly just a handful of cases where something in the standard library won’t fit your needs and will need to be re-implemented.

What’s inside the standard library?

The Clojure standard library is quite comprehensive and can be divided roughly into 3 parts:

  1. What is commonly referred as “core”, the content of the single namespace clojure.core. Core contains the functions that have evolved to be the main public API for the language, including basic math operators, functions to create and manipulate other functions, conditionals. Core currently contains around 700 definitions between functions and macros. Functions in core are always available without any explicit reference from any namespace.
  2. Other namespaces other than core that are shipped as part of the Clojure installation. These are usually prefixed with clojure followed by a descriptive name, like clojure.test, clojure.zippers or clojure.string. Functions in these namespaces are sometimes available just prefixing their namespace (like clojure.string/upper-case) but in other cases they need to be imported in the current namespace using require (this is due to the fact that while bootstrapping, Clojure already imports several namespaces that are automatically available for the end user. Very popular tools like nRepl or Cider also load libraries while bootstrapping, which are then available at the prompt. It is good practice to always require what is useful in a namespace explicitly).
  3. Finally the content of the Java SDK which is easily available as part of Clojure Java interoperability features.

The standard library content can be roughly categorized by looking at the major features Clojure introduces and by the most common programming tasks. There are, for example, big groups of functions dedicated to Software Transactional Memory, concurrency and persistent collections. Of course Clojure also adds all the necessary support for common tasks like IO, sequence processing, math operations, XML, strings and many others. Apparently missing from the Clojure standard library are solutions already provided by the Java SDK, for example cryptography, low-level networking, HTTP, 2D graphics and so on. For all practical purposes those features are not missing, but just usable as they are from Java without the need to re-write them in Clojure. Java interoperability is one of the big strength of Clojure, opening the possibility to easily use the Java SDK (Standard Development Kit) from a Clojure program. Here’s a broad categorization:

  • Core support namespaces integrate core with additional functionalities on top of those already present. clojure.string is possibly the best example. Core already contains str but any other useful string functionalities have been moved out into the clojure.string namespace. clojure.template contains a few helpers for macro creation. clojure.set is about the “set” data structure. clojure.pprint contains formatters for almost all Clojure data types so they can print in a nice, human-readable form. Finally clojure.stacktrace contains function to handle Java exceptions manipulation and formatting.
  • REPL namespaces contain functionalities dedicated to the REPL, the read-evaluation-print-loop Clojure offers. clojure.main includes handling of the main entry point into the Clojure executable and part of the REPL functionalities that have been split into clojure.repl in later time. The latest addition, clojure.core.server implements the server socket functionality.
  • General support is about additional APIs beyond what core has to offer. The namespaces present here enrich Clojure with new functionalities. clojure.walk and clojure.zip for example are two ways to walk and manipulate tree-like data structure. clojure.xml offers XML parsing capabilities. clojure.test is the unit test framework included with Clojure. clojure.sh contains functions to “shell-out” commands to the operative system. clojure.core.reducers offers a model of parallel computation.
  • Java are namespaces dedicated to Java interop beyond what core already has to offer. clojure.java.browser and clojure.java.javadoc offer the possibility to open a native browser to display generic web pages or javadoc documentation respectively. clojure.reflect wraps the Java reflection APIs offering an idiomatic Clojure layer on top of it. clojure.java.io offers a sane approach to java.io, removing all the idiosyncrasies that made Java IO so confusing, like knowing the correct combination of constructors to transform a Stream into a Reader and vice-versa. Finally the clojure.inspector offers a simple UI to navigate data structures.
  • Data Serialization is about ways in which Clojure data can be encoded as string as an exchange format. clojure.edn is the main entry point into (EDN) [https://github.com/edn-format/edn] format serialization. clojure.data contains only one user-dedicated function diff to compute differences between data structures. clojure.instant defines encoding of time related types.

Making Your Development Life Easier

The standard library is not just there to solve the usual recurring programming problems but to offer elegant solutions to new development challenges. “Elegant” in this context translates to composable solutions that are easy to read and maintain. Let’s look at the following example.

Suppose that you’re given the task to create a report to display information on screen in a human readable form. Information is coming from an external system and a library is already taken care of that communication. All you know is that the input arrives structured as the following XML (here saved as a local balance var definition):

The balance needs to be displayed in a user-friendly way:

  1. Removing any unwanted symbols other than letters (like the colon at the beginning of each key)
  2. Separating the words (using uppercase letters as delimiters)
  3. Formatting the balance as a currency with 2 decimal digits.

You might be tempted to solve the problem like this:

  1. parse takes the XML input string and parses it into a hash-map containing just the necessary keys. parse also converts :currentBalance into a double.
  2. clean-key solves the problem of removing the “:” at the beginning of each attribute name. It checks the beginning of the attribute before removing potentially unwanted characters.
  3. separate-words takes care of searching upper-case letters and pre-pending a space. reduce is used here to store the accumulation of changes so far while we read the original string as the input. up-first was extracted as an handy support to upper-case the first letter.
  4. format-decimals handles floating point numbers format. It searches digits with re-find and then either append (padding zeros) or truncate the decimal digits.
  5. Finally print-balance puts all the transformations together. Again reduce is used to create a new map with the transformations while we read the original one. The reducing function was big enough to suggest an anonymous function in a letfn form. The core of the function is assoc the new formatted attribute with the formatted value in the new map to display.

While being relatively easy to read (the 3 formatting rules are somehow separated into functions) the example shows minimal use of what the standard library has to offer. It contains map, reduce, apply and a few others including XML parsing, which are of course important functions (and usually what beginners learn first). But there are definitely other functions in the standard library that would make the same code more concise and readable.

Let’s have a second look at the requirements to see if we can do do a better job. The source of complexity in the code above can be tracked down to the following:

  • String processing: strings need to be analyzed and de-composed. The clojure.string namespace comes to mind and possibly subs.
  • Hash-map related computations: both keys and values need specific processing. reduce is used here because we want to gradually mutate both the key and the value at the same time. But zipmap sounds a viable alternative worth exploring.
  • Formatting rules of the final output: things like string padding of numerals or rounding of decimals. There is an interesting clojure.pprint/cl-format function that might come handy.
  • Other details like nested forms and IO side effects. In the first case threading macros can be used to improve readability. Finally, macros like with-open removes the need for developers to remember to initialize the correct Java IO type and close it at the end.

By reasoning on the aspect of the problem we need to solve, we listed a few functions or macros that might be helpful. The next step is to verify our assumptions and rewrite the example:

  1. parse now avoids the let block, including the annoying side-effect of having to close the input stream by making use of with-open macro. ->> threading macro has been used to give linear flow to the previously nested XML processing.
  2. subs makes really easy to process sub-strings. We don’t need an additional function anymore because turning the first letter to upper-case is now a short single liner.
  3. The key function in the new separate-words version is clojure.string/replace. The regex finds groups of 1 upper-case letter followed by lower-case letters. The last argument conveniently offers the possibility to refer to matching groups. We just need to append a space.
  4. format-decimals delegates almost completely to clojure.pprint/cl-format which does all the job of formatting decimals.
  5. zipmap brings in another dramatic change in the way we process the map. We can isolate changes to the keys (composing words separation and removing the unwanted “:”) and changes to the values into two separated map operations. zipmap conveniently combines them back into a new map without the need of reduce or assoc.

The second example shows an important fact about “knowing your tools” (in this case the Clojure standard library): the use of a different set of functions not only cuts the number of lines from 45 to 30, but also opens up the design to completely different decisions. Apart from the case where we delegated entire sub-tasks to other functions (like cl-format for decimals or int to clean a key), the main algorithmic logic took a different approach that does not use reduce or assoc. A solution that is shorter and more expressive is clearly easier to evolve and maintain.

The well kept secret of the Clojure Ninja

Learning about the functions in the standard library is usually a process that starts at the very beginning. It happens when you first approach some tutorial or book, for example when the author shows a beautiful one-liner that solves an apparently big problem.

Usually developers don’t pay explicit attention to the functions in the standard library, assuming knowledge will somewhat increase while studying the features of the language. This approach can work up to a certain point but it is unlikely to scale. If you are serious about learning the language consider to allocate explicit time to understand the different nuances of similar functions or the content of some obscure namespace. The proof that this is time well spent can be found reading other’s people experience: the web contains many articles describing the process of learning Clojure or documenting discoveries (possibly the best example is Jay Field’s blog).

The following is a trick that works wonders to become a true Clojure Master. Along with learning tools like tutorials, books or exercises like the Clojure Koans, consider adding the following:

  • Select a function from the Clojure standard library every day. It could be lunch or commuting time for example.
  • Study the details of the function sitting in front of you. Look at the official docs first, try out examples at the REPL, search the web or www.github.com for Clojure projects using it.
  • Try to find where the function breaks or other special corner cases. Pass nil or unexpected types as arguments and see what happens.
  • Rinse and repeat the next day.

Don’t forget to open up the sources for the function, especially if belonging to the “core” Clojure namespace. By looking at the Clojure sources, you have the unique opportunity to learn from the work of Rich Hickey and the core team. You’ll be surprised to see how much design and thinking goes behind a function in the standard library. You could even find the history of a function intriguing, especially if it goes back to the origins of Lisp: apply for example, links directly to the MIT AI labs where Lisp was born in 1958! (eval and apply are at the core of the meta-circular interpreter of Lisp fame. The whole Lisp history is another fascinating reading on its own. See any paper from Herbert Stoyan on that matter). Only by expanding your knowledge about the content of the standard library you’ll be able to fully appreciate the power of Clojure.

Summary

  • The standard library is the collection of functions and macros that comes out of the box by installing Clojure.
  • The Clojure Standard Library is rich and robust, allowing developers to concentrate on core business aspects of an application.
  • Information about the Standard Library tends to be fragmented.
  • Deep knowledge of the content of the Standard Library improves code expressiveness exponentially.

Permalink

Functional Programming Is Not What You (Probably) Think

After seeing many of the comments from another article attempting to explain what FP (Functional Programming) is about, I thought I would take another attempt at my own explanation. First, just a little background about me: I am currently a Quality Engineer at Red Hat, and I have been writing Clojure off and on (mostly off) since 2010. I have just recently begun a journey learning PureScript which is (sort of) a dialect of Haskell that targets a JavaScript engine. My goal in this article is to give yet another explanation of FP and give at least a notion of the differences between "mostly" FP from pure FP. I welcome any comments, questions, or corrections (especially with regards to pure functional programming, which I am still fairly new at).

Definition of a Pure Function

So in the previous article mentioned above, the author wanted to convey the notion of what a pure function is: namely, a function which, given the same input, always yields the same output and without any side effects. A side effect can include mutating any variable or affecting the "outside" world (for example writing to a file or stdio). A related but orthogonal concept to a pure function is a total function, which perhaps I'll cover in another article.

Permalink

Reading Clojure

Preamble

Back in early December I held a Clojure workshop for the Bucharest Functional Programming meet up. Having to explain the language to developers who were completely new at it was an interesting experience. I decided to start from the ground up: how to even read the blasted thing.

Reading Clojure

I think what takes people the longest to get used to is how to read the language - particularly if they are already familiar with functional programming semantics. It took me a while to get used to it myself, and even longer to realize why that was.

When reading Java, or C#, we have these markers all over the place. I didn’t even think about them. I had gotten used to just scanning a page of code, paging down, my brain on something else, until my eyes seized. They spotted a public static and then my brain came on, checked if it was the function I cared about, and otherwise it went back into sleep mode while I paged down.

1
2
3
public static int plus_one(int v) {
return v + 1;
}

Clojure’s syntax is very compact. You don’t have these noisy markers when reading code, so you need to be paying attention. You’re going to have much less code to scan through, but your mind needs to be on.

It’s a pleasant change, but it requires practice. We learn by doing, but we also learn by reading what others have done. So I figure the best way to start is to describe how to read Clojure.

Luckily, reading Clojure is trivial. The difficult part actually comes from having to abandon bad habits and expectations of it being more complicated than it is.

Because that’s the second thing I learned. I realized that something that was making it difficult for me to write and read Clojure, was that I was attempting to superimpose on it the more baroque constructs of the languages I was used to.

So let’s dive right in.

Lists and vectors

I thought about easing this in, and talking about code organization and functional programming and what not, but this is important. This is, in fact, the most important bit here.

This is a list: (1 2 3)

This is a vector: [1 2 3]

We’ll talk about how they are different in a bit - it’s mostly about how some functions treat them. For all effects and purposes, the list acts like you would expect a list to act, the vector as an array.

This is also a list: (+ 1 2 3)

This is also a vector: [+ 1 2 3]

That’s it. That is 90% of what you need to know.

Evaluation semantics

The question then is… if this is a list:

1
(1 2 3)

And this is also a list

1
(+ 1 2 3)

Why does the latter get executed and but the second one doesn’t?

Before we go any further, take a step back. Open a text file, make some notes as to the reasons why you’d expect the second line to be an invocation.

Ready?

OK.

In fact, that’s a misconception. When Clojure encounters a non-empty list, it always assumes that they are something to evaluate (either a special form, a macro, or a function). The first value is what’s being invoked, the rest are its parameters.

So in the case of

1
(+ 1 2 3)

It will invoke the function + with the arguments 1, 2 and 3.

Period. Dead simple. That’s it. That’s pretty much all there is to reading Clojure.

As for the first example, if Clojure were to encounter (1 2 3) in the middle of a program, it’ll try to execute it, and expect 1 to be a function. That’ll throw up an error.

There’s a way to avoid that, called “quoting”. We’ll get to that later.

If you’re joining us from Java…

Now, if you are used to C# or Java or Scala, there’s a perfectly normal and reasonable reaction to this. There’s a part of your brain that’s nodding along, thinking “yeah, yeah, homoiconicity, sure“, and at the same time placing a huge asterisk around it.

That asterisk likely points to something saying “well, there’s special cases, like if we need to define a function, or ifs, or a loop. Those things have their own syntax that maybe smells like this, but is different“. Maybe that voice is fine with there being a special case, but it still thinks there is.

Let’s look at some examples to shake off this implicit assumption.

Examples

Let’s look at some cases.

or

1
(or is-right is-kinda-right always-approve)

This is trivial, right? We just apply the logical or function to everything that comes right after. Same thing as when we were adding. No surprise.

In Java we’d have the or in the middle of every value, here we just front-load it. No biggie.

That’s because in Java || is an operator, same way that + is. Java does have some things that are inherent syntax, like the if.

if

So let’s look at what an if is like in Clojure.

1
2
3
(if odd?
(do-something [1 3 5 7])
(do-another-thing [0 2 4 6]))

Aha! We can already see some different things here. Syntax, right? And in fact, if you’ve read about Clojure, you’ve seen that an if is what is called a special form.

Special forms aside

Which is true. Clojure does have something called special forms. One hears special forms and thinks “that’s the stuff that is different“.

It’s not. Not for syntax, and not on how the semantics are evaluated.

What I want you to hear when somebody says special forms is not special cases but primitives. They are things implemented directly into the language, not things that behave differently.

Keep that in mind whenever you see the term come up.

Back to decoding the if

Let’s decode that one for a bit.

1
2
3
(if odd?
(do-something [1 3 5 7])
(do-another-thing [0 2 4 6]))

First of all, there’s the question mark in odd?. That’s not special syntax, but a convention to indicate a value is a boolean. It’s good form to use it, but not necessary.

Then we have the structure that we expect. We have the thing to evaluate (odd?), followed by what to evaluate if true, and what to evaluate if false.

But this is actually not special syntax. The “branches” don’t even need to be “in parenthesis”. Remember: that’s something we do only if we have to evaluate a function. In fact, there are no “branches”, but forms to evaluate in either case, which could just as well just be values.

Therefore, this would be just as valid an if as the one above:

1
2
3
(if got-a-list?
(convert-to-string [1 3 5 7])
"Got something else")

If got-a-list? is true, then Clojure would evaluate the function of converting the list to a string, otherwise it’d just return the string value of the second case (a string evaluates to itself).

Function declaration

Once you’ve grokked that, we should be ready to look at function declaration. Language shapes the way we think, so in order to do that, we should first consider how one’s mind is likely to describe code.

How we think about functions

Let’s go back to how we declare a trivial function in Java.

1
2
3
public static int plus_one(int v) {
return v + 1;
}

Let’s go over how we’d describe what we are looking at here. This might seem like a trivial thing, but don’t skip over it.

  • We have the public keyword, telling us how available the function is,
  • We then have the static keyword, telling us if it belongs to a class or an instance,
  • Then there’s a type the function returns,
  • Then there’s the function name,
  • Then comes the parameter declaration, wrapped in parenthesis,
  • Then there are brackets wrapping a code block,
  • Then there’s the return keyword followed by what to return.

We really have no other way to do it. We need to do this descriptively, think in terms of characters and glyphs that mark what we see. The parenthesis, the brackets, they have no use other than as syntax markers.

defn, round 1

Let’s now look at how we would do this in Clojure. Say, we want to add the “hello world” of functions and re-implement inc:

1
2
(defn plus-one[i]
(+ i 1))

This doesn’t look too bad. Still, that part of your brain might think “well, that’s a special syntax that expects some things in order, like the parameters in brackets, or it gets a syntax error“.

Coming from Java, we might be tempted to read it like this:

  • We have the defn keyword,
  • Then the function name,
  • Then the parameter names in square brackets,
  • Then we just traded the brackets in the body for parenthesis.

Let’s disabuse that part of your brain from the notion right away.

This is just the exact same thing as when we were describing lists and vectors before. If we were to break this down into its elements, we would instead see it as:

1
2
3
4
5
6
(
defn
plus-one
[i]
(+ i 1)
)
  • defn is the name of what’s being invoked. Everything else after it are arguments,
  • The first argument is a symbol specifying the name that the function will be bound to (plus-one),
  • Then there’s an argument that’s a vector with the symbols for the parameter names,
  • The rest is considered implicitly as a list, and its elements will be evaluated one by one.

The result value of a function is the result value of the last item evaluated, in this case, (+ i 1).

But notice the fundamental difference there, which is easy to gloss over. The parameter names are not “in square brackets”, they are a basic data structure containing symbols. Whatever is receiving this symbol vector can manipulate it or pass it to other functions at will.

In fact, defn is not even a special form, it’s not a primitive, and it’s not an inherent part of the language. It’s a macro.

defn, round 2

How about this, then?

1
2
3
4
5
(defn get-from-string
[conn long-url]
(let [url (db/get-url conn long-url)
parsed (db/parse url)]
(clean-up parsed)))

This is, once again, the exact same thing. Let’s break it down, with some nesting to differentiate between the parameter lists and what’s being invoked.

1
2
3
4
5
6
7
8
9
10
(
defn
get-from-string
[conn long-url]
(
let
[url (db/get-url conn long-url) parsed (db/parse url)]
(clean-up parsed)
)
)

Again, we have the defn macro, with the same form as before. Then its first element is another macro, let, which receives as its first parameter a vector of symbol/value pairs.

Let this sink in for a bit. Every case of Clojure code that you encounter will follow this exact same pattern. No matter what that code is or where it comes from, you can be 100% sure that the first value will be the item being invoked, and whatever comes after are arguments.

Even if you see a known function name further down the chain… guess what? That means a function is being passed as an argument.

Tao

This is perhaps the most fundamental thing here. If you take anything from this long spiel, please let it be this bit.

This here is the tao of Clojure syntax. There truly is nothing but the list. In this case, syntax and evaluation semantics are one and the same.

There is nothing that will deviate from this. Value assignment, function invocation, type declaration… it’ll all take the same form.

Quiz!

OK, pop quiz! Are these lines valid Clojure?

1
2
(inc 1)
(inc)

Yes! Both are, as a matter of fact. They are both lists starting with a symbol of a function to invoke. Having said that, the second one will not compile, as the function inc expects some parameters.

Having established that inc is a function, how about these?

1
2
3
inc
[inc]
[inc 1]

These are syntactically valid Clojure as well.

  • inc is merely the symbol associated with the function.
  • [inc] is a vector whose first element is the function inc.
  • [inc 1] is a vector whose first element is the function inc, followed by the element 1.

If Clojure finds any of these, it won’t try to invoke them as it would with a list. It will merely evaluate the function reference, and in the case of the last two, will create a vector with these values. This is useful when you want to pass a function as a parameter to another function.

Having looked at that, would you then expect this to be syntactically valid Clojure?

1
2
3
4
5
(defn a-function [v]
[+ 1 2 3 4 5]
plus-one [inc]
[inc 1]
v)

And it is as well! We are just constructing a list of stuff, some of which are vectors and some of which are symbols. Now, is it semantically valid? As in, will it not only compile, but execute?

Yes! Clojure will go down the list, one by one, and evaluate them. The resulting value will be the last item evaluated, or in this case, v. That’s effectively a very noisy identity function.

Of course, you’re not likely to encounter a function like that. I’m only writing something so odd-looking to eliminate two preconceptions:

  • First, that everything needs to be wrapped in parenthesis. You don’t need to do that unless you’re creating a list or invoking something;
  • Second, that Clojure has all these syntactic special cases that other languages do, only done differently.

Wrapping up

Phew, that was a long read.

If you’re just coming to Clojure, I hope this has helped scrub off some deeply ingrained habits about how to read it. While I haven’t touched on many areas, like sets, keywords, hash maps or meta-data, I thought that clarifying this first was more important. We should also go into how defn is not even a primitive, and just macro combining a few primitives in a single, convenient package, but we’ll get to that later.

Now go out and start getting acquainted with Clojure!

Permalink

SICP in Clojure: Chapter 2 (part 1)

Going on with my study of SICP, this is the first part of chapter 2 (that is a very big chapter and also has a lot of great examples). I also updated the code in the first chapter for some issues with chapter 2 names that were replicated (I made some private definitions there to use refer all here).
The painter example of this book was really cool and actually you can create a painter with Quil library if you want to see it works.


(ns sicp.chapter-2
(:require [sicp.chapter-1 :refer :all]))

;Common functions
(defn null? [l] (and (seq? l) (empty? l)))
;Chapther 2: Building Abstractions with Data
(defn linear-combination [a b x y]
(+ (* a x) (* b y)))
(declare add mul)
(defn linear-combination [a b x y]
(add (mul a x) (mul b y)))

;Chapter 2.1.1
(declare make-rat numer denom)
(defn add-rat [x y]
(make-rat (+ (* (numer x) (denom y))
(* (numer y) (denom x)))
(* (denom x) (denom y))))
(defn sub-rat [x y]
(make-rat (- (* (numer x) (denom y))
(* (numer y) (denom x)))
(* (denom x) (denom y))))
(defn mul-rat [x y]
(make-rat (* (numer x) (numer y))
(* (denom x) (denom y))))
(defn div-rat [x y]
(make-rat (* (numer x) (denom y))
(* (denom x) (numer y))))
(defn equal-rat? [x y]
(= (* (numer x) (denom y))
(* (numer y) (denom x))))
(def x (cons 1 [2]))
(first x)
(second x)
(def x (cons 1 [2]))
(def y (cons 3 [4]))
(def z (cons x (cons y [])))
(first (first z))
(first (second z))
(defn make-rat [x y] (cons x [y]))
(def numer first)
(def denom second)
(defn print-rat [x]
(println "")
(println (str (numer x) "/" (denom x))))
(def one-half (make-rat 1 2))
(print-rat one-half)
(def one-third (make-rat 1 3))
(print-rat (add-rat one-half one-third))
(print-rat (mul-rat one-half one-third))
(print-rat (add-rat one-third one-third))
(defn make-rat [n d]
(let [g (gcd n d)]
(cons (/ n g) [(/ d g)])))

(print-rat (add-rat one-third one-third))
(defn make-rat [n d]
(cons n [d]))
(defn numer [x]
(let [g (gcd (first x) (second x))]
(/ (first x) g)))
(defn denom [x]
(let [g (gcd (first x) (second x))]
(/ (second x) g)))
(print-rat (add-rat one-third one-third))
(defn cons [x y]
(letfn [(dispatch [m]
(cond (= m 0) x
(= m 1) y
:else (println "Argument not 0 or 1: CONS" m)))]
dispatch))
(defn car [z] (z 0))
(defn cdr [z] (z 1))

;Exercise 2.4
(defn cons [x y]
#(% x y))
(defn car [z]
(z (fn [p q] p)))

(defn cdr [z]
(z (fn [p q] q)))

;Exercise 2.6
(def zero (fn [f] (fn [x] x)))
(defn add-1 [n]
(fn [f] (fn [x] (f (n f) x))))

;Chapters 2.1.4
(declare make-interval lower-bound upper-bound)
(defn add-interval [x y]
(make-interval (+ (lower-bound x) (lower-bound y))
(+ (upper-bound x) (upper-bound y))))
(defn mul-interval [x y]
(let [p1 (* (lower-bound x) (lower-bound y))
p2 (* (lower-bound x) (upper-bound y))
p3 (* (upper-bound x) (lower-bound y))
p4 (* (upper-bound x) (upper-bound y))]
(make-interval (min p1 p2 p3 p4)
(max p1 p2 p3 p4))))
(defn div-interval [x y]
(mul-interval
x
(make-interval (/ 1.0 (upper-bound y))
(/ 1.0 (lower-bound y)))))

;Exercise 2.7
(defn make-interval [a b]
(cons a [b]))
(defn upper-bound [x] (first x))
(defn lower-bound [x] (second x))

;Exercise 2.11
(defn make-center-width [c w]
(make-interval (- c w) (+ c w)))
(defn center [i]
(/ (+ (lower-bound i) (upper-bound i)) 2))
(defn width [i]
(/ (- (upper-bound i) (lower-bound i)) 2))

;Exercise 2.13
(defn par1 [r1 r2]
(div-interval (mul-interval r1 r2)
(add-interval r1 r2)))
(defn par2 [r1 r2]
(let [one (make-interval 1 1)]
(div-interval
one (add-interval (div-interval one r1)
(div-interval one r2)))))

;Chapter 2.2.1
(def cons clojure.core/cons)
(cons 1
(cons 2
(cons 3
(cons 4 nil))))
(list 1 2 3 4)
(def one-through-four (list 1 2 3 4))
(first one-through-four) ;first instead of car
(rest one-through-four) ;rest instead of car
(first (rest one-through-four))
(cons 10 one-through-four)
(cons 5 one-through-four)

;List Operations
(defn list-ref [items n]
(if (= n 0)
(first items)
(list-ref (rest items) (- n 1))))
(def squares (list 1 4 9 16 25))
(list-ref squares 3)
(defn length [items]
(if (empty? items)
0
(+ 1 (length (rest items)))))
(def odds (list 1 3 5 7))
(length odds)
(defn length [items]
(letfn [(length-iter [a count]
(if (empty? a)
count
(length-iter (rest a) (+ 1 count))))]
(length-iter items 0)))
(defn append [list1 list2]
(if (empty? list1)
list2
(cons (first list1) (append (rest list1) list2))))
(append squares odds)
(append odds squares)

;Exercise 2.19
(def us-coins (list 50 25 10 5 1))
(def uk-coins (list 100 50 20 10 5 2 1 0.5))
(declare no-more? except-first-denomination)
(defn cc2-19 [amount coin-values]
(cond (= amount 0) 1
(or (< amount 0) (no-more? coin-values)) 0
:else
(+ (cc amount
(except-first-denomination coin-values))
(cc (- amount
(first-denomination coin-values))
coin-values))))

;Exercise 2.20
(comment (defn fn-name [ & <parameters>] <body>)
(def f (fn [x y & z] <body>))
(def g (fn [& w] <body>)))

;Mapping over a list
(defn scale-list [items factor]
(if (empty? items)
nil
(cons (* (first items) factor)
(scale-list (rest items) factor))))
(scale-list (list 1 2 3 4 5) 10)

(defn map-ex [proc items]
(if (empty? items)
nil
(cons (proc (first items))
(map-ex proc (rest items)))))
(map-ex abs (list -10 2.5 -11.6 17))
(map #(* % %) (list 1 2 3 4))
(defn scale-list [items factor]
(map #(* % factor) items))
;Exercise 2.21
(declare <??>)
(defn square-list [items]
(if (empty? items)
nil
(cons <??> <??>)))
(defn square-list [items]
(map <??> <??>))

;Exercise 2.22
(defn square-list [items]
(letfn [(iter [things answer]
(if (empty? things)
answer
(iter (rest things)
(concat (square (rest things))
answer))))]
(iter items nil)))
(defn square-list [items]
(letfn [(iter [things answer]
(if (empty? things)
answer
(iter (rest things)
(cons answer
(concat (rest things))))))]
(iter items nil)))

;Exercise 2.23
(def for-each map)
(for-each (fn [x]
(println "")
(println x))
(list 57 321 88))

;Chapter 2.2.2
(defn count-leaves [x]
(cond (and (seq? x) (empty? x)) 0
((complement seq?) x) 1
:else (+ (count-leaves (first x))
(count-leaves (rest x)))))
(cons (list 1 2) (list 3 4))
(def x (cons (list 1 2) (list 3 4)))
(length x)
(count-leaves x)
(list x x)
(length (list x x))
(count-leaves (list x x))

;Exercise 2.26
(def x (list 1 2 3))
(def y (list 4 5 6))
(append x y)
(cons x y)
(list x y)

;Exercise 2.27
(def x (list (list 1 2) (list 3 4)))
x
(reverse x)
(comment (deep-reverse x))

;Exercise 2.29
(defn make-mobile [left right]
(list left right))
(defn make-branch [length structure]
(list length structure))

;Mapping over trees
(defn scale-tree [tree factor]
(cond (null? tree) nil
((complement seq?) tree) (* tree factor)
:else (cons (scale-tree (first tree) factor)
(scale-tree (rest tree) factor))))
(scale-tree (list 1 (list 2 (list 3 4) 5) (list 6 7)) 10)
(defn scale-tree [tree factor]
(map (fn [sub-tree]
(if (seq? sub-tree)
(scale-tree sub-tree factor)
(* sub-tree factor)))
tree))

;Exercise 2.31
(declare tree-map)
(defn square-tree [tree] (tree-map square tree))

;Exercise 2.32
(defn subsets [s]
(if (null? s)
(list nil)
(let [rest (subsets (rest s))]
(concat rest (map <??> rest)))))

;Chapter 2.2.3
(defn sum-odd-squares [tree]
(cond (null? tree) 0
(not (seq? tree)) (if (odd? tree)
(square tree)
0)
:else (+ (sum-odd-squares (first tree))
(sum-odd-squares (rest tree)))))
(defn even-fibs [n]
(letfn [(next [k]
(if (> k n)
nil
(let [f (fib k)]
(if (even? f)
(cons f (next (+ k 1)))
(next (+ k 1))))))]
(next 0)))

;Sequence Operations
(map square (list 1 2 3 4 5))
(defn filter [predicate sequence]
(cond (null? sequence) nil
(predicate (first sequence)) (cons (first sequence)
(filter predicate (rest sequence)))
:else (filter predicate (rest sequence))))
(filter odd? (list 1 2 3 4 5))
(defn accumulate [op initial sequence]
(if (null? sequence)
initial
(op (first sequence)
(accumulate op initial (rest sequence)))))
(accumulate + 0 (list 1 2 3 4 5))
(accumulate * 1 (list 1 2 3 4 5))
(accumulate cons nil (list 1 2 3 4 5))
(defn enumerate-interval [low high]
(if (> low high)
nil
(cons low (enumerate-interval (+ low 1) high))))
(enumerate-interval 2 7)
(defn enumerate-tree [tree]
(cond (null? tree) nil
(not (seq? tree)) (list tree)
:else (concat (enumerate-tree (first tree))
(enumerate-tree (rest tree)))))
(enumerate-tree (list 1 (list 2 (list 3 4)) 5))
(defn sum-odd-squares [tree]
(accumulate
+ 0 (map square (filter odd? (enumerate-tree tree)))))
(defn even-fibs [n]
(accumulate
cons nil (filter even? (map fib (enumerate-interval 0 n)))))
(defn list-fib-squares [n]
(accumulate
cons nil (map square (map fib (enumerate-interval 0 n)))))
(list-fib-squares 10)
(defn product-of-squares-of-odd-elements [sequence]
(accumulate * 1 (map square (filter odd? sequence))))
(product-of-squares-of-odd-elements (list 1 2 3 4 5))
(letfn [(salary [] <??>)
(programmer? [] <??>)]
(defn salary-of-highest-paid-programmer [records]
(accumulate max 0 (map salary (filter programmer? records)))))

;Exercise 2.23
(defn map-2.23 [p sequence]
(accumulate (fn [x y] <??> nil sequence)))
(defn append-2.23 [seq1 seq2]
(accumulate cons <??> <??>))
(defn length-2.23 [sequence]
(accumulate <??> 0 sequence))

;Exercise 2.34
(defn horner-eval [x coefficient-sequence]
(accumulate (fn [this-coeff higher-term] <??>)
0
coefficient-sequence))

;Exercise 2.35
(defn count-leaves-2.35 [t]
(accumulate <??> <??> (map <??> <??>)))

;Exercise 2.36
(defn accumulate-n [op init seqs]
(if (null? (first seqs))
nil
(cons (accumulate op init <??>)
(accumulate-n op init <??>))))

;Exercise 2.37
(defn dot-product [v w]
(accumulate + 0 (map * v w)))
(defn matrix-*-vector [m v]
(map <??> m))
(defn transpose [mat]
(accumulate-n <??> <??> mat))
(defn matrix-*-matrix [m n]
(let [cols (transpose n)]
(map <??> m)))

;Exercise 2.38
(def fold-right accumulate)
(defn fold-left [op initial sequence]
(letfn [(iter [result rest-seq]
(if (null? rest)
result
(iter (op result (first rest-seq))
(rest rest-seq))))]
(iter initial sequence)))
(fold-right / 1 (list 1 2 3))
(try
(fold-left / 1 (list 1 2 3))
(catch Exception e))
(fold-right list nil (list 1 2 3))
(try (fold-left list nil (list 1 2 3))
(catch StackOverflowError e))

;Exercise 2.39
(defn reverse-1 [sequence]
(fold-right (fn [x y] <??>) nil sequence))
(defn reverse-2 [sequence]
(fold-left (fn [x y] <??>) nil sequence))

;Nested Mappings
(let [n 4]
(accumulate
append nil (map (fn [i]
(map (fn [j] (list i j))
(enumerate-interval 1 (- i 1))))
(enumerate-interval 1 n))))
(defn flatmap [proc seq]
(accumulate append nil (map proc seq)))
(defn prime-sum? [pair]
(prime? (+ (first pair) (first (rest pair)))))
(defn make-pair-sum [pair]
(list (first pair) (first (rest pair)) (+ (first pair) (first (rest pair)))))
(defn prime-sum-pairs [n]
(map make-pair-sum
(filter prime-sum? (flatmap
(fn [i]
(map (fn [j] (list i j))
(enumerate-interval 1 (- i 1))))
(enumerate-interval 1 n)))))
(defn permutations [s]
(letfn [(remove [item sequence]
(filter (fn [x] (not (= x item))) sequence))]
(if (null? s)
(list nil)
(flatmap (fn [x]
(map (fn [p] (cons x p))
(permutations (remove x s))))
s))))

;Exercise 2.42
(letfn [(empty-board [] <??>)
(safe? [] <??>)
(adjoin-position [] <??>)]
(defn queens [board-size]
(letfn [(queen-cols [k]
(if (= k 0)
(list empty-board)
(filter
(fn [positions] (safe? k positions))
(flatmap
(fn [rest-of-queens]
(map (fn [new-row]
(adjoin-position
new-row k rest-of-queens))
(enumerate-interval 1 board-size)))
(queen-cols (- k 1))))))]
(queen-cols board-size))))

;Exercise 2.43
(comment
(flatmap
(fn [new-row]
(map (fn [rest-of-queens]
(adjoin-position new-row k rest-of-queens))
(queen-cols (- k 1))))
(enumerate-interval 1 board-size)))

;Chapter 2.2.4 A Picture Language
(declare wave beside flip-vert flip-horiz below up-split corner-split
sub-vect make-vect add-vect origin-frame draw-line start-segment
end-segment)
(defn flipped-pairs [painter]
(let [painter2 (beside painter (flip-vert painter))]
(below painter2 painter2)))
(comment
(def wave2 (beside wave (flip-vert wave)))
(def wave4 (below wave2 wave2))
(def wave4 (flipped-pairs wave)))
(defn right-split [painter n]
(if (= n 0)
painter
(let [smaller (right-split painter (- n 1))]
(beside painter (below smaller smaller)))))
(defn up-split [painter n]
(if (= n 0)
painter
(let [smaller (up-split painter (- n 1))]
(below painter (beside smaller smaller)))))
(defn corner-split [painter n]
(if (= n 0)
painter
(let [up (up-split painter (- n 1))
right (right-split painter (- n 1))]
(let [top-left (beside up up)
bottom-right (below right right)
corner (corner-split painter (- n 1))]
(beside (below painter top-left)
(below bottom-right corner))))))
(defn square-limit [painter n]
(let [quarter (corner-split painter n)]
(let [half (beside (flip-horiz quarter) quarter)]
(below (flip-vert half half)))))
(defn square-of-four [tl tr bl br]
(fn [painter]
(let [top (beside (tl painter) (tr painter))
bottom (beside (bl painter) (br painter))]
(below bottom top))))
(defn flipped-pairs [painter]
(let [combine4 (square-of-four identity flip-vert
identity flip-vert)]
(combine4 painter)))
(def rotate180 (comp flip-vert flip-horiz))
(defn square-limit [painter n]
(let [combine4 (square-of-four flip-horiz identity
rotate180 flip-vert)]))
(defn frame-coord-map [frame]
(fn [v]
(add-vect
(origin-frame frame))))

;Exercise 2.47
(defn make-frame [origin edge1 edge2]
(list origin edge1 edge2))

;Painters
(defn segments->painter [segment-list]
(fn [frame]
(for-each (fn [segment]
(draw-line
((frame-coord-map frame)
(start-segment segment))
((frame-coord-map frame)
(end-segment segment))))
segment-list)))
;Transforming and combining painters
(defn transform-painter [painter origin corner1 corner2]
(fn [frame]
(let [m (frame-coord-map frame)]
(let [new-origin (m origin)]
(painter (make-frame
new-origin
(sub-vect (m corner1) new-origin)
(sub-vect (m corner2) new-origin)))))))
(defn flip-vert [painter]
(transform-painter painter
(make-vect 0.0 1.0)
(make-vect 1.0 1.0)
(make-vect 0.0 0.0)))
(defn shrink-to-upper-right [painter]
(transform-painter
painter (make-vect 0.5 0.5)
(make-vect 1.0 0.5) (make-vect 0.5 1.0)))
(defn rotate80 [painter]
(transform-painter painter
(make-vect 1.0 0.0)
(make-vect 1.0 1.0)
(make-vect 0.0 0.0)))
(defn squash-inwards [painter]
(transform-painter painter
(make-vect 0.0 0.0)
(make-vect 0.65 0.35)
(make-vect 0.35 0.65)))
(defn beside [painter1 painter2]
(let [split-point (make-vect 0.5 0.0)]
(let [paint-left
(transform-painter
painter1
(make-vect 0.0 0.0)
split-point
(make-vect 0.0 1.0))
paint-right
(transform-painter
painter2
split-point
(make-vect 1.0 0.0)
(make-vect 0.5 1.0))]
(fn [frame]
(paint-left frame)
(paint-right frame)))))

Permalink

Copyright © 2009, Planet Clojure. No rights reserved.
Planet Clojure is maintained by Baishamapayan Ghose.
Clojure and the Clojure logo are Copyright © 2008-2009, Rich Hickey.
Theme by Brajeshwar.