Functional Programming in Clojurescript
Priyatam Mudivarti
Principal, Facjure
Understanding
REPL
Understanding (parens)
Data Structures
Functions, Closures, HoF
Data Flow
Exploring
HTML5
CSS3
Templating
IDEs
Libraries
Agenda
Complex?
Templates
client apis
Build Tools
Responsive Design
Events
Dom
Performance
Modules
3rd party libs
Javascript
event handling, dynamic, ajax, json
CSS3/Less/Sass
rules, selectors,
responsive design
HTML5
markup , templating, dom
Simpler
How?
FP in Cljs
my version, anyway.
It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures
- Alan J. Perlis
A data structure is just a stupid programming language
— R. Wm. Gosper
Data
Composition
Abstractions
Really, there's nothing else
You don't have to worry about
build plugins
mvc frameworks
modules
load-times
bundling
3rd party "functional" libs
optimization (dead code elimination)
Data structures in Cljs
immutable, lazy sequences
functions that create sequences
functions that filter sequences
sequence predicates
functions that transform sequences
;; Unlike JavaScript there is no hoisting in ClojureScript. ClojureScript has lexical scoping.
(def some-x 1)
(let [some-x 2]
some-x)
;; functions parameters, let bindings locals, and loop locals are not mutable!
(let [fns (loop [i 0 ret []]
(if (< i 10)
(recur (inc i) (conj ret (fn [] i)))
ret))]
(map #(%) fns))
Scopes
; simple function
(defn add [a b]
(+ a b))
;; function with multiple args and default values
(defn another-function
([x] (defaults x :default))
([x y] [x y]))
;; closure
(let [a 1e3]
(defn foo []
(* a a))
(defn bar []
(+ (foo) a)))
;; higher order functions
Functions
(def a-vector [1 2 3 4 5])
(def a-nested-map
{:customer-id 1e6
:preferences {:nickname "Bob"
:avatar "http://en.gravatar.com/userimage/0/0.jpg"}
:services {:alerts {:daily true}}})
(def complex-map
{[1 2] :one-two
[3 4] :three-four})
(def a-set
#{:cat :dog :bird})
Basic Data structures
(defn clearfix [clazz]
[clazz {:*zoom 1}
[:&:before :&:after {:display "table"
:content " "
:line-height 0}]
[:&:after {:clear "both"}]])
CSS as Data
[
{:poem/title "I am not a hacker"}
{:poem/book :poets-and-hackers}
{:poem/year 2015}
{:author/name "Priyatam Mudivarti"}
{:author/email "priyatam@facjure.com"}
{:author/gender :male}
{:tag/names #{:hackers :poetry-slam :boulder-cafe :fp-rocks}
{[1 2] :one-two }}
]
Edn, a data transfer format
[
{:poem/title "I am not a hacker"}
{:poem/book :poets-and-hackers}
{:poem/year 2015}
{:author/name "Priyatam Mudivarti"}
{:author/email "priyatam@facjure.com"}
{:author/gender :male}
{:tag/names #{:hackers :poetry-slam :boulder-cafe :fp-rocks}
{[1 2] :one-two }}
]
Json as Data
(def header-snippet
[:header
[:h1 "Mala"]
[:h3 "A User Interface template in Clojurescript."]])
(def footer-snippet
[:footer
[:a {:href "https://twitter.com/priyatam"} "@priyatam"]])
(defn view [{:keys [active path name]}]
(html
[:section {:class "home"}
header-snippet
[:nav
[:ul
[:li {:class (if active "active" "")}
[:a {:href (str "#" path)} name]]]]
footer-snippet]))
HTML/Templating as Data
;; Plain old Ajax
(defn handler [response]
(.log js/console (str response)))
(defn error-handler [{:keys [status status-text]}]
(.log js/console (str "something bad happened: " status " " status-text)))
(GET "/hello" {:handler handler
:error-handler error-handler})
;; Core.Async
(defn GET [res handler]
(go (let [response (<! (http/get res {:with-credentials? false}))]
(logp (:body response))
(handler (:body response)))))
Ajax / Async Http as Data
(ns brutha.example
(:require [brutha.core :as br :refer [mount]]
[sablono.dom :as dom]))
(mount
(html [:p "Hello World"])
(js/document.getElementById "app"))
React components as Data
;; list comprehension
(for [x (range 1 10)
y (range 1 10)
:when (and (zero? (rem x y))
(even? (quot x y)))]
[x y])
List comprehensions
;; higher order functions over sequences
(map inc [0 1 2 3 4 5 6 7 8 9])
(filter even? (range 10))
(reduce + (range 100))
(partition 2 [:a 1 :b 2 :c 3 :d 4 :e 5])
(remove odd? (range 10))
(take 5 (interleave (repeat "red") (repeat "blue")))
Higher-order functions
Abstraction is at the center of most work in
Computer Science &
User Interface Design.
Abstractions
a lot more
transducers, pmap, comp ...
(map
(comp - (partial + 3) (partial * 2))
[1 2 3 4])
;;=> (-5 -7 -9 -11)
Let's talk about CSS/SASS
no namespaces
can't compose HTML and CSS in the same syntax
css doesn’t “talk to dom”
math impl is hard
can we pass css as functions at runtime?
mixins are not composable
constrained by limitations—not by choice
programming stylesheets
in FP
separate selectors and declarations
Ring-style middleware
Mesh, a grid & typography library
http://github.com/facjure/mesh
(defn create-minimal-grid [clazz pad]
[[:* {:box-sizing "border-box"}]
[clazz {:background "white"
:margin [[0 0 pad 0]]}
[:&:after {:content ""
:display "table"
:clear "both"}]
["[class*='col-']" {:float "left"
:padding-right pad }]
[:.col-1-3 {:width "33.33%"}]
[:.col-2-3 {:width "66.66%"}]
[:.col-1-2 {:width "50.00%"}]
[:.col-1-4 {:width "25.00%"}]
[:.col-1-8 {:width "12.50%"}]
[:.out-padding {:padding [[pad 0 pad pad pad]]}
["[class*='col-']:last-of-type"
{:padding-right pad}]]]])
A grid in a single function
So
everything is Data
a sequence of values
pipe, compose
Exercise #1
a simple autocomplete
markup in cljs data structures
styles in clojurescript data structures
event handling as functions
Exercise #3
Om/React
markup in cljs data structures
styles in clojurescript data structures
event handling as functions
Exercise #3
markdown editor
single-page app with html5 local-storage
Exercise #4
Responsive Design
css3
References
Demos created with https://github.com/priyatam/mala
https://github.com/facjure/mesh Libraries https://github.com/omcljs/om https://github.com/noprompt/garden https://github.com/noprompt/secretary
https://github.com/bhauman/lein-figwheel
https://slides.com/priyatam/functional-programming-with-cljs
@priyatam
priyatam@facjure.com
http://github.com/priyatam
Functional Programming in Cljs
By Priyatam Mudivarti
Functional Programming in Cljs
Clojurescript is an FP language that targets the Browser, Node, and Rhino. As a subset of Clojure, Cljs compiles to an optimized Js, and provides a solid foundation for building and designing user-interfaces with immutable data structures, first-class namespaces, scopes, and a minimalist syntax that does more with less.
- 396