Clojure – Your new favorite language – Lisp



Clojure – Your new favorite language – Lisp

0 0


Clojure-Presentation


On Github atscott / Clojure-Presentation

Clojure

Created by Andrew Scott

What We'll Cover

  • Lisp
  • Data Handling in Clojure

Lisp

List Processing

THIS IS A VERTICAL SLIDE

Code is Data. Data is Code.

It turns out that Lisp source code is actually a valid data structure called an abstract syntax tree (AST). This makes metaprogramming easier since code can be treated as a basic data structure that the programming language knows how to access.

Metaprogramming?

It means that a program could be designed to read, generate, analyse or transform other programs, and even modify itself while running

Homoiconicity

basically means the program structure is similar to its syntax, and therefore the program’s internal representation can be inferred by reading the text’s layout. What this allows you to do is extend the functionality of the language and manipulate it on the fly at runtime. In other languages, we would have to recompile from human-language source code into valid syntax tree before it is compiled into code. THIS IS A VERTICAL SLIDE

Homoiconicity Example

(+ 2 4)
; => 6
This adds 2 and 4 but it is also list of 3 items in a valid data structure.
(def example (list '+ (+ 1 1) (+ 2 2)))
; => (+ 2 4)
(eval example)
; => 6
(read-string "(+ 2 4)")
; => (+ 2 4)
                
(eval (read-string "(+ 2 4)"))
; => 6
                
Why is this useful?

Macros and Clojure

So what are some of the benefits of a language being homoiconic? It makes it relatively easy to write DSLs. One of the more powerful effects of being homoiconic though is the ability to define custom macros. Macros in essence allow you to define new language features as a developer. In most languages you would need to wait for a new release of the language to get new syntax – in Lisp (and Clojure) you can just extend the core language with macros and add the features yourself.

'when' macro

(when (true) (println “hello”))
; => “hello”
                
(macroexpand ‘(when (true) (println “hello”)))
; (if (true) (do (println “hello”)))
                
(defmacro when
    "Evaluates test. If logical true, evaluates body in an implicit do."
    {:added "1.0"}
    [test & body]
    (list 'if test (cons 'do body)))
                

Aren't macros just functions?

You could do something similar with functions, but it’s not the same. Functions execute at run-time, they take and produce data (values). Macros execute at compile-time, they take and produce code. Macros arguments are not evaluated and their return values are expanded-in-place and treated as code. Functions Macros Execute at runtime Execute at compile-time Take and produce data (values) Take and produce code
Questions

So Clojure is a Lisp... What else?

Data Manipulation Guarantees

  • The old version remains accessible
  • The new version can be produced efficiently
  • Both versions satisfy the complexity guarantees
The new version can be produced while meeting the time complexity guarantees of the data structure. For example, adding to the end of a list should take constant time. Some people have attempted in the past to cheat where the latest version is as fast as you would expect but older versions sort of decay. There is no cheating going on in Clojure so even old versions meet the complexity guarantees.

How?

  • Data structures are hash array mapped tries
  • Shallow with high branching factors
  • Structural Sharing
is an implementation of an associative array that combines the characteristics of a hash table and an array mapped trie. It is a refined version of the more general notion of a hash tree. draw a HAMT What does it mean to add to the end? 1. Take the last array, copy it (bounded size of 32 so it's constant time) 2. copy the path to the root 3. New root, new path to the right side, but everything else is shared So the left trie has a million items in it, and you only change 3 nodes on the right side to add something to the end.

What does this mean?

So instead of saying "change this thing in place", you say "call this transformation function which gives a new thing and give me that". That changes your life. Now you can share these things in a way that you could never before because with an object, you don't know if you have to clone it, if it's going to change, etc.

Structure of your program

C#, Java, etc. Clojure Direct references to things that can change Indirect references to thing that never change Concurrency is all convention, all manual Concurrency semantics are built in Traditionally composed of direct references to things that can change. As soon as you've done that, you are stuck with locking and managing synchronization. Why is this bad? Everything is manual and everything is convention (we're locking A before B, we're locking alphabetically, there's a lock over here for these 3 things, don't forget to lock before you do this). Where does all this go? Contrast with Clojure: Rather than having things actually change, you have indirect references to things that can never change. But those references can be made to refer to other things over the course of the application. Gives the same effect of changing over time. Clojure has concurrency semantics for these references. Because they are indirect, your program isn't just twiddling them, your program has to use functions to make them point to different things. And those functions have concurrency semantics. Which means that they're automatic, the language helps you change the things to point to other things and not mess that up, and it's enforced. For instance, some references can only be changed inside a transaction; if you try to change it outside a transaction it throws an exception. Big difference - all convention, all manual. Clojure - things never change. If you dereference one of the references, you get an immutable object. If someone makes that reference point to something else while you're doing calculations, do you care? No. There are also no locks in the application program.

Review

  • Lisp (List Processing)
  • Structural Sharing
  • Concurrency differences

References

Clojure Created by Andrew Scott