You are on page 1of 53

Abstraction Oriented Programming

Functioneel Programmeren op de JVM met Clojure

Who? Rik van Achterberg


Brian van der Bijl Wouter Hassing Mahijs Steen

From?

Hogeschool Utrecht

When? Juni

Presentatie

Inleiding Doel van het onderzoek Casus: RichRail Verschillen met Java Onderwijs Conclusie

Inleiding

Wat is Clojure?
1 (defn square [x] (* x x)) 2 ; define the function square 3 ; [x] is the parameter 4 ; (* x x ) = x * x = x^2

Inleiding

Wat is Functioneel Programmeren?


1 (defn double [x] (* 2 x)) 2 (map double [1 2 3]) 3 ; Dit heeft hetzelfde resultaat als 4 ; [(double 1) (double 2) (double 3)] = [2 4 6]

Inleiding

Wat is Functioneel Programmeren?


1 (defn double [x] (* 2 x)) 2 (map double [1 2 3]) 3 ; Dit heeft hetzelfde resultaat als 4 ; [(double 1) (double 2) (double 3)] = [2 4 6]

Waarom is dit interessant?

Doel van het onderzoek

Vragen
Wat zijn de voornaamste verschillen tussen Clojure en Java?

Doel van het onderzoek

Vragen
Wat zijn de voornaamste verschillen tussen Clojure en Java? Wat zijn de voornaamste voor- en nadelen van Functioneel Programmeren in Clojure t.o.v. Object-georienteerd Programmeren in Java?

Doel van het onderzoek

Vragen
Wat zijn de voornaamste verschillen tussen Clojure en Java? Wat zijn de voornaamste voor- en nadelen van Functioneel Programmeren in Clojure t.o.v. Object-georienteerd Programmeren in Java? Zou de Hogeschool Utrecht er goed aan doen om Functioneel Programmeren in het informatica-curriculum op te nemen?

Versillen met Java

OO versus FP

Versillen met Java

OO versus FP

Versillen met Java

OO vs. FP
Encapsulation

Closures

Versillen met Java

OO vs. FP
Encapsulation

Closures
1 (defn create [] 2 3

(let [remembers 5] (fn [] remembers)))

4 (println ((create)))

Versillen met Java

OO vs. FP
Encapsulation

Closures
1 (defn create [] 2 3

(let [remembers 5] (fn [] remembers)))

4 (println ((create)))

Namespaces

Versillen met Java

OO vs. FP
Encapsulation

Closures
1 (defn create [] 2 3

(let [remembers 5] (fn [] remembers)))

4 (println ((create)))

Namespaces Immutability

Inheritance

1 class Person { 2 public String getFullName () { /* body */ } 3 } 4 class Employee extends Person { 5 public BusinessCard getBusinessCard () { /* body */ } 6 }

Inheritance

1 (defn full-name [x] 2

(str (:first-name x) (:last-name x)))

3 (defn business-card [x] 4

[(full-name) (: mail-address x)])

Inheritance

It is beer to have functions operate on one data structure than to have functions operate on data structures. - Alan J. Perlis

Versillen met Java

OO versus FP Statisch versus Dynamisch

Statis vs. Dynamis

Clojure is dynamisch getypeerd Traditioneel zijn LISPs altijd dynamisch Dynamic typed system is eenvoudiger te implementeren Macros en code on runtime aanpassen zouden praktisch onmogelijk zijn met een statisch typering

Versillen met Java

OO versus FP Statisch versus Dynamisch Recursie versus Iteratie

Recursie vs. Iteratie

De functionele oplossing voor iteratie is recursie Tail recursion optimalization

Casus: RiRail

Paerns and Frameworks From PoorRail to Richrail

RiRail: Java design

RiRail: Clojure

RiRail: Clojure

Clojure is niet OO

RiRail: Clojure

Clojure is niet OO Hoe representeer je een depot, trein, wagon?

RiRail: Clojure

Clojure is niet OO Hoe representeer je een depot, trein, wagon?


1 (def depot (atom [(list) (list)])) 2 (def train {:train id :twagons (list)}) 3 (def wagon {:wagon id :seats seats :status :free})

RiRail: Clojure

Commandos
Functies op collecties

RiRail: Clojure

Commandos
Functies op collecties Lijst van treinen lijst van treinen

RiRail: Clojure

Commandos
Functies op collecties Lijst van treinen lijst van treinen Lien naar depot

RiRail: Clojure

Commandos
Functies op collecties Lijst van treinen lijst van treinen Lien naar depot Lien naar atom

RiRail: Clojure
Commandos
1 (defn- try-if-exists [exist id f error] 2 3 4 5 6 7 (defn- new-train [id] 8 9

(fn [coll] (if ((exists? exist) (some (comp (partial = id) obj-id) coll)) (f coll) [coll [(str > error)]])))

(try-if-exists :no id (fn [coll] [(cons {:train id :twagons (list)} coll) [(str > train id created)]])

10

(str no train created , id exists!)))

RiRail: Clojure
Commandos
1 (defn- get-wagon [id] 2 3

(try-if-exists :yes id (fn [coll] [coll [(str > number of seats in wagon id : (:seats (find-object coll id)))]])

4 5

(str wagon id does not exist)))

6 (defn- del-vehicle [id] 7 8

(try-if-exists :yes id (fn [coll] [(remove (comp (partial = id) obj-id) coll) [(str > id deleted)]])

(str id not deleted , it wasnt there to begin with!)))

RiRail: Clojure

1 (defn- do-to-both [wfunc tfunc] 2 3 4 5 6 (def in-both do-to-both) 7 8 (defn- modify! [at funcs] 9 10 11 12 13

(fn [depot] (with-monad log-m ((m-chain [(in-trains tfunc) (in-wagons wfunc)]) depot))))

(let [action

(with-monad log-m (m-chain funcs))

[_ msg] (action @at)] (swap! at (comp first action)) (doseq [msg msg] (println msg)) (str-join \n msg)))

RiRail: Clojure
Easy-access
1 (defn- new-wagon-cmd [id & seats] (in-wagons (new-wagon id (first

seats))))
2 (defn- new-train-cmd [id] (in-trains (new-train id))) 3 (defn- get-wagon-cmd [id] (in-wagons (get-wagon id))) 4 (defn- get-train-cmd [id] (in-trains (get-train id))) 5 (defn- add-wagon-to-train-cmd [wid tid] 6

(in-both (set-wagon wid :connected) (wagon-to-train wid tid)))

7 (defn- remove-wagon-from-train-cmd [wid tid] 8

(in-both (set-wagon wid :free) (wagon-from-train wid tid)))

9 (defn- del-wagon-cmd [id] 10

(in-both (del-vehicle id) (wagon-from-train id (connected-train id))))

11 (defn- del-train-cmd [id] 12

(in-both (release-wagons id) (del-vehicle id)))

RiRail: Clojure

Parsers
Simpele functies om bijvoorbeeld karakters te parsen

RiRail: Clojure

Parsers
Simpele functies om bijvoorbeeld karakters te parsen Dankzij monads makkelijk te combineren tot complexe parsers

RiRail: Clojure

Parsers
Simpele functies om bijvoorbeeld karakters te parsen Dankzij monads makkelijk te combineren tot complexe parsers Parsers zijn functies, en kunnen dus alles wat een functie kan

RiRail: Clojure
Parsers
1 (defn- any-char [strn] 2 3 4

(if (= strn) nil (list (first strn) (. strn (substring 1)))))

5 (defn- char-test [pred] 6 7 8 9

(domonad parser-m [c any-char :when (pred c)] (str c)))

10 (defn- is-char [c] 11

(char-test (partial = c)))

RiRail: Clojure
Parsers
1 (defn- match-string [target-strn] 2 3 4 5 6 7

(with-monad parser-m (if (= target-strn) (m-result ) (domonad parser-m [c (is-char (first target-strn)) cs (match-string (apply str (rest target-strn) ))]

8 9 (def id-parser 10 11

(str c cs)))))

(with-monad parser-m (both (m-plus (match-string wg) (match-string tr)) number)) )

12 (def type-parser 13

(with-monad parser-m (m-plus (match-string wagon) ( match-string train))))

RiRail: Clojure
Parsers
1 (def new-command-parser 2 3 4 5 6 7 8 9 10 11 12 13 14

(domonad parser-m [ _ _ obj-type _ id seats ] (if (= obj-type train) (fn [depot] (modify! depot [( new-train-cmd id)])) (if (nil? seats) (fn [depot] (modify! depot [( new-wagon-cmd id)])) (fn [depot] (modify! depot [( new-wagon-cmd id seats)]))) ))) (match-string new) whitespace type-parser whitespace id-parser (optional numseats-parser)

RiRail: Clojure

1 (def parse-command 2

(with-monad parser-m (m-plus add-command-parser new-command-parser get-command-parser delete-command-parser remove-command-parser print-command-parser)))

3 4 (defn- do-evaluate [string] 5

(eval ((first (parse-command string)) depot)))

RiRail: Clojure

Interop
UIs in Clojure bestaan voornamelijk uit interop

RiRail: Clojure

Interop
UIs in Clojure bestaan voornamelijk uit interop In plaats daarvan interop gebruikt om aan Java versie te koppelen

RiRail: Clojure

Interop
UIs in Clojure bestaan voornamelijk uit interop In plaats daarvan interop gebruikt om aan Java versie te koppelen Zet Clojure structuren om in Java structuren

RiRail: Clojure
Interop
1 (ns com.richrail.interop.state 2 3 4 5 6 7 8 9 10

(:gen-class :name com.richrail.state.ClojureStateProvider :prefix method:implements [com.richrail.state.StateProvider ]) (:import java.util.ArrayList com.richrail.state.DepotState com.richrail.state.TrainState com.richrail.state.WagonState) (:use com.richrail.core))

11 (defn train- >object [train] 12

(TrainState. (obj-id train) (ArrayList. (reverse (map (fn [id] ( wagon- >object (find-object wagons @depot id))) (:twagons train) )))))

13 (defn method-getState [_] 14

(DepotState. (ArrayList. (map train- >object (reverse (trains @depot))))

15

(ArrayList. (map wagon- >object (reverse (wagons

Onderwijs

FP in het onderwijs?

Onderwijs

FP in het onderwijs? Onze ervaring

Onderwijs

FP in het onderwijs? Onze ervaring Wij zeggen: doen!

Conclusie

Clojure is

Conclusie

Clojure is Declaratief vs Imperatief

Conclusie

Clojure is Declaratief vs Imperatief Functioneel vs OOP

Conclusie

Clojure is Declaratief vs Imperatief Functioneel vs OOP Onderwijs

You might also like