Music, Art, and Web Apps in Clojure
Clojure is a programming language.
- Modern Lisp
- Pragmatic
- Runs on JVM (also JavaScript!)
- Dynamic, optionally static typing
- Functional
- Immutable
- Concurrent
- BDFL - Rich Hickey
A Modern Lisp
- 2nd oldest high-level programming language (1958)
- Invented by John McCarthy
- Based on Lambda Calculus
Brief History of Lisp
- Common Lisp
- Scheme
- Clojure
- Emacs Lisp
11+ currently maintained Lisp dialects
Lisp Overview
- Polish Prefix Notation
- REPL
- LISt Processing
- Lots of Parentheses
- (s-expressions)
- Pioneer of recursion, conditionals, higher order functions, etc.
- Macros
Lisp Syntax
(defun square (x)
(* x x))
(square (5)) ; => 25
(+ (* 2 3) 1) ; => 7
REPL
Lisp primitive functions
- Read - accepts an expression from the user, and parses it into a data structure
- Eval - evaluates the data structure (function or list) and returns result
- Print - prints the result back to the user
- Loop - returns back to Read, looping until there is nothing left to read
LISt Processing
(setq list '(1 2 3))
(defun sum (list)
(if (null list) ;; conditional like JS ternary operator!
0
(+ (first list)
(sum (rest list))))) ; => 6
Everything's a list (s-expressions)
Macros
Meta programming
(defmacro inc (x)
(list 'setq x (list '1+ x)))
(inc 5) ; expands to (setq 5 (1+ 5))
; evals to => 6
Lisp in the real world
- ViaWeb, the original e-commerce site (Paul Graham)
- Jak and Daxter (Naughty Dog)
- Super Mario 64 (Nintendo)
- Emacs (GNU, Richard Stallman)
- Aritficial Intelligence
Back to Clojure
Syntax
(defn hello [] ;; Minor differences from CL, notice defn instead of defun
"Hello World!"
) ;; Args use square brackets
(hello) ;=> "Hello World!"
(+ (* 2 3) 1) ;=> still 7
- Most widely-contributed-to Clojure project
- Akin to Maven and Grunt in a way, but far more integral to development
- Like Ruby Gems or Node modules, a Clojure library repo.
- Clojure contrib was official but seemingly dead (or in less use than clojars)
Targets JVM and JavaScript
- Super fast run time (at the expense of a super slow compile/start up time)
- Compiles to JVM byte code
- Also compiles directly to JavaScript with ClojureScript
- Can import Java Libraries and export to .jars and .wars
Immutable
- Basically means unchangeable
- Can change the reference to the object or data, but not the object or data itself
- In order for data to be modified, we must get a new copy of data
- Prevents unwanted modifications via inheritance, other unknown factors
Functional
- Stateless
- Mathematical
- Immutable
- Paradigm akin to OOP
Concurrent
- Multiple simultaneous computations
- Separate computations can interact with each other
- Difficult, but Clojure is good at it
- Multithreading
- Full-stack micro-framework
- Built on Ring middleware
- Multiple application profiles
- Insanely simple
Demo
$ lein new luminus lumi-demo +cljs +h2 // generate project with database and clojurescript
$ cd lumi-demo
$
$ lein run // start app
// Poke through the code while server starts up, go to localhost:3000
$ git clone git@github.com:luminus-framework/guestbook.git
$ cd guestbook
$ lein ragtime migrate // migrate database
$ lein run
// Again visit localhost:3000, show off database workings
- Built on SuperCollider (sound software)
- Live code music
- MIDI interface
- Freesound API
Demo
$ lein new overtone-demo
$ cd overtone-demo
$ emacs
;; add [overtone "0.9.1"] to :dependencies in project.clj
$ lein deps
;; cider-jack-in or $ lein repl
Demo
;; overtone-demo/core.clj
(ns overtone-demo.core
(:use
[overtone.live :refer :all])
(def hihat (sample (freesound-path 250530)))
(def kick (sample (freesound-path 2086)))
(def snare (sample (freesound-path 212208)))
(defonce met (metronome 180))
(defn drum-loop [m beat]
(at (m (+ 0 beat)) (kick) (hihat))
(at (m (+ 0.5 beat)) (hihat))
(at (m (+ 1 beat)) (snare) (hihat))
(at (m (+ 1.5 beat)) (hihat))
(at (m (+ 2 beat)) (kick) (hihat))
(at (m (+ 2.5 beat)) (hihat))
(at (m (+ 3 beat)) (snare) (hihat))
(apply-at (m (+ 4 beat)) drum-loop m (+ 4 beat) [])
)
(drum-loop met (met))
- Built on Processing (graphics software)
- Live code visuals
- 2d and 3d
- Interactive and animated
Demo
$ lein new quil-demo
$ cd quil-demo
$ emacs
;; add [quil "2.2.5"] to :dependencies in project.clj
$ lein deps
;; cider-jack-in or $ lein repl
Demo
;; quil-demo/core.clj
(ns quil-demo.core
(:require [quil.core :as q]))
(defn setup []
(q/smooth)
(q/frame-rate 30))
(defn draw []
(q/stroke (q/random 255) (q/random 255) (q/random 255))
(q/stroke-weight (q/random 50))
(q/fill (q/random 255) (q/random 255) (q/random 255))
(let [diam (q/random 180)
x (q/random (q/width))
y (q/random (q/height))]
(q/ellipse x y diam diam)))
(q/defsketch demo
:title "Random colorful circles"
:setup setup
:draw draw
:size [1292 800])
Overtone + Quil
Demo
$ lein new quilover-demo
$ cd quilover-demo
$ emacs
;; add [quil "2.2.5"] and [overtone "0.9.1"] to :dependencies in project.clj
$ lein deps
;; cider-jack-in or $ lein repl
Overtone + Quil
Demo
;; quilover-demo/core.clj
(ns quilover-demo.core
(:require [quil.core :as q]
[overtone.live]))
(defn setup []
(q/smooth)
(q/stroke-weight (q/random 50))
(q/fill 150 50)
(q/set-state! :mouse-position (atom [0 0])))
(def boing (sample (freesound-path 140867)))
(defn draw-circles []
(dorun
(for [i (range 0 300)]
(let [x (q/random (q/width))
y (q/random (q/height))
radius (+ (q/random 100) 60)]
(q/ellipse x y (* 2 radius) (* 2 radius))
(q/stroke (q/random 255) (q/random 255) (q/random 255))
(q/fill (q/random 255) (q/random 255) (q/random 255))
(q/ellipse x y (q/random 500) (q/random 500))))))
(defn capture-click []
(let [[x y] @(q/state :mouse-position)]
(boing)
(draw-circles)))
(q/defsketch gen-art-30
:title "Click Boing Shapes"
:setup setup
:mouse-pressed capture-click
:size [900 600])
Other Sources
- radar.oreilly.com/2015/05/creative-computing-with-clojure.html
- github.com/vervas/overtone-clj
- people.cs.umass.edu/~liberato/home/blog/2013/02/01/overtone-and-clojurescript-updated/
- wikipedia.com
- www.cs.utexas.edu/~mtimkvch/lisp_tutorial.html
- github.com/philandstuff/skillsmatter-overtone-examples
- pragprog.com/book/dswdcloj/web-development-with-clojure