Last active
December 17, 2015 23:49
-
-
Save brianstorti/5692240 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; sum the square of the parameters. | |
(def add-squares | |
(fn [& args] | |
(apply + (map * args args)))) | |
(add-squares 1 2 5) | |
; factorial without iteration/recursion. | |
(def factorial | |
(fn [number] | |
(apply * (range 1 (inc number))))) | |
(factorial 5) | |
(take 2 [1 2 3]) | |
(repeat 4 [1]) | |
(interleave [1 2] [4 5]) | |
(drop 1 (drop-last 1 [1 2 3])) | |
(flatten [1 2 [3 4]]) | |
(partition 2 [1 2 3 4 5 6]) | |
(every? even? [2 4 6]) | |
(def prefix-of | |
(fn [candidate sequence] | |
(= (take (count candidate) sequence) candidate))) | |
(prefix-of [1 2] [1 2 3 4]) ; true | |
(prefix-of [1 2 3 1] [1 2 3 4]) ; false | |
(def tails | |
(fn [seq] | |
(map drop | |
(range (inc (count seq))) | |
(repeat (inc (count seq)) seq)))) | |
(tails [1 2 3 4]) | |
(repeat (inc (count [1 2 3 4])) [1 2 3 4]) | |
(range (inc (count [1 2 3 4]))) | |
{:a 5, :b "2"} ; a map. in clojure, commas are white spaces, the reader ignores them | |
(get {:a 5, :b "2"} :a) ; unusual | |
(:b {:a 3, :b 2}) ; keywords act like a function when places as the first element of a list | |
({:a 1 :b 2} :a) | |
(apply hash-map [:x 1 :y 2]) | |
(def do-something-to-map | |
(fn [function] | |
(function {:a "a value", :b "another value"}))) | |
(do-something-to-map :a) | |
(do-something-to-map count) | |
(assoc {:a 1} :b 2, :c 3, :d 4) | |
(assoc {:a 1} :a 2) | |
(merge {:a 1} {:b 2} {:c 3}) | |
(dissoc {:a 1 :b 2 :c 3} :b :a) | |
; minimal class | |
(def Point | |
(fn [x y] | |
{:x x, | |
:y y})) | |
; three ways to implement an "x" accessor | |
(def x | |
(fn [this] | |
(get this :x))) | |
(def x | |
(fn [this] (:x this))) | |
(def x :x) | |
(def y :y) | |
(x (Point 1 2)) ; call the accessor to get the value of "x" | |
(def Point | |
(fn [x y] | |
{:x x, | |
:y y, | |
:__class_symbol__ 'Point})) | |
(def class-of :__class_symbol__) | |
(class-of (Point 1 2)) | |
(def shift | |
(fn [point x-inc y-inc] | |
(Point (+ (x point) x-inc) | |
(+ (y point) y-inc)))) | |
(shift (Point 1 200) -2 -100) | |
; add function not using shift | |
(def add | |
(fn [point1 point2] | |
(Point (+ (x point1) (x point2)), | |
(+ (y point1) (y point2))))) | |
(add (Point 1 3) (Point 3 4)) | |
; using shift | |
(def add-with-shift | |
(fn [point1 point2] | |
(shift point1 (x point2) (y point2)))) | |
(add-with-shift (Point 1 3) (Point 3 4)) | |
(def make | |
(fn [type & args] | |
(apply type args))) | |
(make Point 1 1) | |
(def Triangle | |
(fn [point1 point2 point3] | |
{:point1 point1 | |
:point2 point2 | |
:point3 point3 | |
:__class_symbol__ 'Triangle})) | |
(def right-triangle (Triangle (Point 0 0) | |
(Point 0 1) | |
(Point 1 0))) | |
(def equal-right-triangle (Triangle (Point 0 0) | |
(Point 0 1) | |
(Point 1 0))) | |
(def different-triangle (Triangle (Point 0 0) | |
(Point 0 10) | |
(Point 10 0))) | |
(def equal-triangles? | |
(fn [source target] | |
(and | |
(= (:point2 source) (:point2 target)) | |
(= (:point3 source) (:point3 target)) | |
(= (:point1 source) (:point1 target))))) | |
(def equal-triangles? =) | |
(equal-triangles? right-triangle right-triangle) | |
(equal-triangles? right-triangle equal-right-triangle) | |
(equal-triangles? right-triangle different-triangle) | |
; there are no repeated points | |
(def valid-triangle? | |
(fn [& points] | |
(= points (distinct points)))) | |
(valid-triangle? (Point 1 1) (Point 1 2) (Point 1 3)) | |
(def send-to | |
(fn [object message & args] | |
(apply (message (:__methods__ object)) object args))) | |
(def Point | |
(fn [x y] | |
{:x x | |
:y y | |
:__class_symbol__ 'Point | |
:__methods__ { | |
:class :__class_symbol__ | |
:x :x | |
:y :y | |
:shift | |
(fn [this x-inc y-inc] | |
(make Point (+ (send-to this :x) x-inc) | |
(+ (send-to this :y) y-inc))) | |
}})) | |
(def point (make Point 1 2)) | |
(:shift (:__methods__ point)) | |
(print ((:shift (:__methods__ point)) point -2 -3)) | |
(def Point { | |
:__own_symbol__ 'Point | |
:__instance_methods__ | |
{ | |
:add-instance-values | |
(fn [this x y] | |
(assoc this :x x :y y)) | |
:shift | |
(fn [this xinc yinc] | |
(make Point (+ (:x this) xinc) | |
(+ (:y this) yinc))) | |
} | |
}) | |
(def make | |
(fn [class & args] | |
(let [seeded { :__class_symbol__ (:__own_symbol__ class) } | |
constructor (:add-instance-values | |
(:__instance_methods__ class))] | |
(apply constructor seeded args)))) | |
(def point (make Point 1 2)) | |
(def send-to | |
(fn [object message & args] | |
;; the "eval" is needed because we get the *symbol* Point, not the value this symbol is bound to | |
(let [class (eval (:__class_symbol__ object)) | |
method (message (:__instance_methods__ class))] | |
(apply method object args)))) | |
(send-to point :shift -2 -3) | |
(def method-from-name | |
(fn [message class] | |
(message (:__instance_methods__ class)))) | |
(def apply-message-to | |
(fn [class instance message args] | |
(apply (method-from-name message class) instance args))) | |
(def make | |
(fn [class & args] | |
(let [seeded { :__class_symbol__ (:__own_symbol__ class) }] | |
(apply-message-to class seeded :add-instance-values args)))) | |
(def send-to | |
(fn [object message & args] | |
(let [class (eval (:__class_symbol__ object))] | |
(apply-message-to class object message args)))) | |
(send-to (make Point 5 5) :shift -2 -3) | |
(def class-from-instance | |
(fn [instance] | |
(eval (:__class_symbol__ instance)))) | |
(def Point | |
{ | |
:__own_symbol__ 'Point | |
:__instance_methods__ | |
{ | |
:add-instance-values (fn [this x y] | |
(assoc this :x x :y y)) | |
:class-name :__class_symbol__ | |
:class (fn [this] (class-from-instance this)) | |
:shift (fn [this xinc yinc] | |
(make Point (+ (:x this) xinc) | |
(+ (:y this) yinc))) | |
:add (fn [this other] | |
(send-to this :shift (:x other) | |
(:y other))) | |
} | |
}) | |
(def point (make Point 1 2)) | |
(send-to point :class-name) | |
(send-to point :class) | |
(def Holder | |
{ | |
:__own_symbol__ 'Holder | |
:__instance_methods__ | |
{ | |
:add-instance-values (fn [this held] | |
(assoc this :held held)) | |
} | |
}) | |
(def method-from-message | |
(fn [message class] | |
(message (:__instance_methods__ class)))) | |
; search for accessor method, if it's not found, get the "variable" | |
(def apply-message-to | |
(fn [class object message args] | |
(let [method (or (method-from-message message class) | |
message)] | |
(apply method object args)))) | |
(def send-to | |
(fn [object message & args] | |
(let [class (eval (:__class_symbol__ object))] | |
(apply-message-to class object message args)))) | |
(send-to (make Holder "stuff") :held) | |
;; Inheritance | |
(declare class-from-instance send-to make) | |
(def Point | |
{ | |
:__own_symbol__ 'Point | |
:__superclass_symbol__ 'Anything ;; <<= New | |
:__instance_methods__ | |
{ | |
:add-instance-values (fn [this x y] | |
(assoc this :x x :y y)) | |
:shift (fn [this xinc yinc] | |
(make Point (+ (:x this) xinc) | |
(+ (:y this) yinc))) | |
:add (fn [this other] | |
(send-to this :shift (:x other) | |
(:y other))) | |
} | |
}) | |
(def Anything | |
{ | |
:__own_symbol__ 'Anything | |
:__instance_methods__ | |
{ | |
:add-instance-values identity | |
:class-name :__class_symbol__ | |
:class (fn [this] (class-from-instance this)) | |
} | |
}) | |
(def class-symbol-above | |
(fn [class-symbol] | |
(assert (symbol? class-symbol)) | |
(:__superclass_symbol__ (eval class-symbol)))) | |
(def recursive-function | |
(fn [class-symbol] | |
(if (nil? class-symbol) | |
nil | |
(cons class-symbol | |
(recursive-function (class-symbol-above class-symbol)))))) | |
(recursive-function 'Point) | |
(def lineage-1 | |
(fn [class-symbol so-far] | |
(if (nil? class-symbol) | |
so-far | |
;; "recur" tell the JVM you have a tail recursion, so it can be optimized | |
(recur (class-symbol-above class-symbol) | |
(cons class-symbol so-far))))) | |
(def lineage | |
(fn [class-symbol] | |
(lineage-1 class-symbol []))) | |
(lineage 'Point) | |
(def factorial | |
(fn [number] | |
(if (or (= number 1) (= number 0)) | |
1 | |
(* number (factorial (dec number)))))) | |
(factorial 0) | |
(factorial 1) | |
(factorial 5) | |
(def factorial-tail-recursion | |
(fn [number so-far] | |
(if (or (= number 1) (= number 0)) | |
so-far | |
(recur (dec number) | |
(* so-far number))))) | |
(def factorial | |
(fn [number] | |
(factorial-tail-recursion number 1))) | |
(factorial 5) | |
(factorial 0) | |
(factorial 1) | |
(def recursive-add | |
(fn [numbers so-far] | |
(if (empty? numbers) | |
so-far | |
(recur (rest numbers) | |
(+ so-far (first numbers)))))) | |
(recursive-add [1 2 3 4 5 6] 0) | |
(def recursive-multiply | |
(fn [numbers so-far] | |
(if (empty? numbers) | |
so-far | |
(recur (rest numbers) | |
(* so-far (first numbers)))))) | |
(recursive-multiply [1 2 3 4] 1) | |
(def recursive-function | |
(fn [operation numbers so-far] | |
(if (empty? numbers) | |
so-far | |
(recur operation | |
(rest numbers) | |
(operation so-far (first numbers)))))) | |
(recursive-function + [1 2 3 4] 0) | |
(recursive-function * [1 2 3 4] 1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment