29
CPL 2016, week 10 Clojure functional core Oleg Batrashev Institute of Computer Science, Tartu, Estonia April 11, 2016

CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

CPL 2016, week 10Clojure functional core

Oleg Batrashev

Institute of Computer Science, Tartu, Estonia

April 11, 2016

Page 2: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Overview

TodayI Clojure language core

Next weeksI Immutable data structuresI Clojure simple state and designI Software transactional memoryI Agents in Clojure

Page 3: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 3/32 -

Overview

I Declarative programming (DP)I what is declarativeness

I Immutable data structuresI lists, trees

I DP basicsI iterative comutationI recursive computation

I Declarative concurrency (DC)I DP and DC in Haskell and other languages

Page 4: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 4/32 Declarative programming -

Outline

Functional coreDeclarative programmingClojure immutable code-dataBasics of declarative programming

Page 5: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 5/32 Declarative programming -

Some quotes

I Recent “Effective Scala” from Twitter developershttp://twitter.github.com/effectivescala/

I Use Futures to manage concurrency.I Futures allow the programmer to express concurrent

computation in a declarative styleI If an immutable collection will do, use it ... reasoning about

them in a concurrent context is simple.I The Java memory model is a subtle beast, but luckily we can

avoid all of these pitfalls by using the declarative style

What is declarative style, future and immutable collection and howare they special?

Page 6: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 6/32 Declarative programming -

What is declarativeness

An operation with input and output is declarativeI Same input always gives the same output

I independent (of outside state)I stateless (no inside state)I deterministic (“fixed” control-flow)I no side effects (no writing to IO or outside state)

ExamplesI typical algebraic operations (+,-,*,/)I if-then-elseI pure functions

Page 7: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 7/32 Declarative programming -

Declarativeness is important

I CompositionalI plug declarative component

Declarativeoperation

arguments

results

Rest ofcomputation

I Reasoning is simpleI understand component behaviour aloneI no need to consider external/internal state

Page 8: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 8/32 Declarative programming -

In Clojure (and other FP)

I variables are immutableI function arguments, loop variables, local (let) variablesI except def, defn creates global mutable variables

I standard data structures are immutable (persistent)I list, vector, map, set

I pure functionsI no side effects: i.e. no IO/shared state read or write

Page 9: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 9/32 Clojure immutable code-data -

Outline

Functional coreDeclarative programmingClojure immutable code-dataBasics of declarative programming

Page 10: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 10/32 Clojure immutable code-data -

Running code

I REPL (read-eval-print loop)

$ clojureClojure 1.6.0user=> (+ 4 5)9user=> (println "Hello ")Hello

I Create file with extension ’clj’ and run it with clojureI use def to define global variables

(def x 5)(println "Hello" x)

I avoid them for now, because they are not part of declarativemodel

Page 11: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 11/32 Clojure immutable code-data -

Lisp syntaxI parentheses () play an important role

I almost always call a function

(fnname arg1 arg2 arg3)

I no infix operators, so even adding 2 values

(+ 2 3)

I try to read this

(+ (/ (* 2 5) 3) (- 1 2))

I quoting – do not execute the function

'(+ 2 3)

I returns linked list of 3 values: + function, integers 2 and 3I + is function value (reference to the value)

I code is data, in the form of linked lists!

Page 12: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 12/32 Clojure immutable code-data -

Basic typesI booleans, integers, rationals, floats

(println true false 5 (/ 1 4) 0.25)

I characters, strings(println \H "ello")

I keywords are symbolic constants (like in Erlang)(println :keyw1 (type :keyw2)); -> :keyw1 clojure.lang.Keyword

I symbols are names for variables, functions, etcI difficult to catch – compiler tries to substitute for their values

(println sym1); -> CompilerException ... Unable to resolve symbol: sym1

I but they are real

(println 'sym1 (class 'sym1)); -> sym1 clojure.lang.Symbol

Page 13: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 13/32 Clojure immutable code-data -

Immutable linked lists

I (list 3 4 7) or with quoting '(3 4 7)

I actual representation (cons 3 (cons 4 (cons 7 ())))

I empty list () ends the listI “cons” pair (cons H T) consists of

I head H references one list valueI tail T references the rest of the list

I first/rest – accessing head and tailI destructuring: extract head and tail

(let [[H & T] '(3 4 7)] (println T) )

I prints (4 7)

I changing an element in the list is impossibleI adding head (cons 11 lst), also (conj lst 11)

Page 14: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 14/32 Clojure immutable code-data -

Appending lists

I Appending a=(1 2 3) b=(6 7) must result in copying the first list(cons 1 (cons 2 (cons 3 b)))

1 2 3 6 7

1 2 3

Append one list to another by just reassigning the tail?No!

I the first list must stay immutableI whoever has reference to it should not see changes

I the second list may be appended to any otherI whoever has reference to it sees no changes

Page 15: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 15/32 Clojure immutable code-data -

Variables

I single-assignment variables – you can only assign value onceI let construct, x and y are not re-assignable

(let [x 5y 10]

(println (- x y)))

I function arguments (x,y) are not re-assignable

(fn [x y] (* x y))

I def assigns to things called vars, return to them in 2 weeks

(def f (fn [x y] (* x y)))(println (f 5 10))

I they are re-assignable

Page 16: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 16/32 Clojure immutable code-data -

Static scoping

Variables/parameters are only seen within scopeI let – define local symbols and execute statements

clojure.core/let(let [bindings *] exprs*)

I fn – parameter symbols seen within function scope

clojure.core/fn(fn name? [params *] exprs*)(fn name? ([ params *] exprs*) +)

I for – local symbols seen with ’for’ scope

(for [x (range 10)y (range 5):let [z (+ x y)]:when (< z 10)]

(list x y z))

Page 17: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 17/32 Clojure immutable code-data -

Defining functions – don’t panic

I fn defines anonymous function

(fn [arg1 arg2 arg3] stm1 stm2 stm3)

I def assigns value to global variable

(def sym val)

I the rest is just syntactic sugar

(defn f1 [arg1 arg2] stm1 stm2 stm3); assigns function to global variable 'f1'

I letfn for local functions

(letfn [(f2 [x y](println :we)(- x y))]

(println (f2 2 3)))

Page 18: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 18/32 Basics of declarative programming -

Outline

Functional coreDeclarative programmingClojure immutable code-dataBasics of declarative programming

Page 19: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 19/32 Basics of declarative programming -

Iterative computation (1)

How to iterate over values with single-assignment variable?I with recursionI each (recursive) call creates new variables for the arguments

(defn iteration [X Sum](if (>= X 10)

Sum ; stop and return result(do ; else

(println X)(iteration (inc X) (+ Sum X)))))

(println (iteration 0 0))

Page 20: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 20/32 Basics of declarative programming -

Iterative computation (2)I On the third iteration

"Result"

"X"

"Sum"

x1 0 s1 0

x2 1 s2 0

x3 2 s3 1

current call

I new values are created on the stack in each callI recursion stops at x10

I old xi and si can safely be used by external code/threads(unlike in imperative PLs)

I Java ’final’ keyword for closures

Page 21: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 21/32 Basics of declarative programming -

Clojure ’recur’

I avoid stack grow with ’recur’I must be in tail positionI calls current function with tail call optimization (TCO)I JVM does not allow TCO, Clojure has to generate iterative

code instead of recursive calls

(defn iteration [i s](if (>= i 10)

s(do ; else

(println i)(recur (inc i) (+ s i)))))

(println (iteration 0 0))

Page 22: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 22/32 Basics of declarative programming -

Recursive computation (1)

I Naive implementations are often wastefulI stack grows because of append is not in tail position

(defn append [Ls Ms](if (= Ls ())

Ms(cons (first Ls) (append (rest Ls) Ms))))

(println (append '(1 5 3) '(3 2 3)))

I Naive definitions are often slow

(defn reverse [Xs](if (= Xs ())

'()(append (reverse (rest Xs))

(list (first Xs)) )))(println (reverse '(1 2 3 4)))

Page 23: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 23/32 Basics of declarative programming -

Recursive computation (2)

Use accumulators and tail recursion

(defn - reverse2_iter [Rs Ys](if (= Ys '())

Rs ; return accumulated result(recur (cons (first Ys) Rs) (rest Ys))))

(defn reverse2 [Xs](reverse2_iter '() Xs)) ; empty accumulator

(println (reverse2 '(1 4 3 2)))

I Rs is an accumulator for the new listI Recursive call is in tail positionI same with reduce

(def P (fn [acc val] (cons val acc )))(reduce P [] [1 2 7])

Page 24: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 24/32 Basics of declarative programming -

Recursion example( de f l e t t e r T y p e s #{Cha ra c t e r /LOWERCASE_LETTER

Cha rac t e r /UPPERCASE_LETTER})( de fn l e t t e r ? [ ch ] ( l e t t e r T y p e s ( Cha r a c t e r / getType ch ) ) )

( defn− scan−word [ r e a d e r word ]"Read s i n g l e word from the r e a d e r . "( l e t [ ch ( . r ead r e a d e r ) ]

( i f ( l e t t e r ? ch )( r e c u r r e a d e r ( cons ch word ) )( app l y s t r (map char ( r e v e r s e word ) ) ) ) ) )

( defn− scan−words−imp l [ r e a d e r words ]( l e t [ ch ( . r ead r e a d e r ) ] ; r ead next symbol

( i f (= ch −1) ; i s end o f r e a d e r ?words ; f i n i s h and r e t u r n words

( i f ( l e t t e r ? ch ); ; scan the word( r e c u r r e a d e r ( con j words ( scan−word r e a d e r ( l i s t ch ) ) ) ); ; s k i p c h a r a c t e r( r e c u r r e a d e r words ) ) ) ) )

( de fn scan−words [ r e a d e r ]( scan−words−imp l r e a d e r [ ] ))

Page 25: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 25/32 Basics of declarative programming -

Higher-order programming (1)

Reverse the list (1 2 7)1

(P .)

2

(P .)

7

(P .)() (1) (2 1) (7 2 1)

I accumulator values from R0=() to R3=(7 2 1)I can be also viewed as state transform from S0 to S3I tansformation takes In and X and returns Out

Out ← (P In X)

(P .)In

XOut

Page 26: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 26/32 Basics of declarative programming -

Higher-order programming (2)

Define the generic function

(defn forAllAcc [Lst P Acc](if (empty? Lst)

Acc(let [[X & Tail] Lst ; split the list

NewAcc (P Acc X)] ; update accum(recur Tail P NewAcc )))) ; proceed with the rest

; use sum as the transform function(println (forAllAcc [1 2 3] + 0)); use prepend as the transform function(let [prepend (fn [a x] (cons x a))]

(println (forAllAcc [1 2 3] prepend ())))

I forAllAcc is actually foldlI state transform view: X may be incoming message

Page 27: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 27/32 Basics of declarative programming -

Idiomatic functional operations

I filter – filter each element of the list according to the predicateI list + predicate = list

I map – transform each element of the listI list + transform function = list

I fold (reduce) – reduce all elements of the list using givenfunction

I list + reduction function = scalarI [X Y Z] and * as the reduction function (notation is not

Clojure)I (X*Y)*Z for left foldingI X*(Y*Z) for right folding

Page 28: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 28/32 Basics of declarative programming -

Clojure collections

I vectors: [1 2 3], (vector 1 2 3), (vec ’(1 2 3))I maps: {:key1 "val", :key2 42, 99 "ok"}

(class {:key1 "val"}); -> clojure.lang.PersistentArrayMap

I with constructor: (hash-map :key1 "val")

I sorted map (sorted-map :key1 2)

I sets: #{:val1 "str" 12}

I sorted set ...I seq interface: seq, first, rest, next

Page 29: CPL 2016, week 10 - Clojure functional core...CPL 2016, week 10 - Clojure functional core Author Oleg Batrashev Created Date 4/11/2016 5:11:31 AM

Functional core 29/32 Basics of declarative programming -

Sequence library in Clojure

I conj, intoI range, repeat, repeatedly, iterateI take, cycleI interleave, interpose (join)I constructors (list, vector, hash-set, hash-map)

I compare to vec

I filter, take-while, drop-while, split-at, split-withI every?, someI map, reduce, sort, sort-byI for – does map + filter