Last active
June 12, 2018 10:58
-
-
Save beatngu13/af0b4e09d80e9540d27903d5173a6dc1 to your computer and use it in GitHub Desktop.
Fun with Clojure
This file contains hidden or 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
;;;;;;;;;; | |
;;;; Fun with Clojure | |
;;;;;;;;;; | |
;; Comments are based on Peter Norvig's recommendations from his tutorial on | |
;; good Lisp programming style (see | |
;; http://www.cs.umd.edu/~nau/cmsc421/norvig-lisp-style.pdf on page 41): | |
;; ; inline comment | |
;; ;; in-function comment | |
;; ;;; between-function comment | |
;; ;;;; section header | |
;;;;;;;;;; | |
;;; Map, filter and any | |
;;;;;;;;;; | |
(defn my-map [func collection] | |
(for [value collection] (func value))) | |
(defn my-filter [predicate collection] | |
(remove (complement predicate) collection)) | |
(defn my-any [predicate collection] | |
(let [head (first collection)] | |
(if (predicate head) | |
head | |
(recur predicate (rest collection))))) | |
(my-map #(* 2 %) [0 1 2 3 4]) | |
;;=> [0 2 4 6 8] | |
(my-filter even? [0 1 2 3 4]) | |
;;=> [0 2 4] | |
(my-any odd? [0 1 2 3 4]) | |
;;=> 1 | |
;;;;;;;;;; | |
;;; Fractions | |
;;;;;;;;;; | |
(def my-ratio 2/3) | |
;;=> 'user/my-ration | |
(+ my-ratio (/ 1 3)) | |
;;=> 1N | |
;;;;;;;;;; | |
;;; Factorial alternatives | |
;;;;;;;;;; | |
;; Simple recursion. | |
(defn factorial1 [n] | |
(if (zero? n) | |
1 | |
(* n (factorial1 (dec n))))) | |
;; Use BigInt. | |
(defn factorial2 [n] | |
(if (zero? n) | |
1N | |
(*' n (factorial2 (dec n))))) | |
;; Hide arity by defining a Closure. | |
(defn factorial3 [n] | |
(loop [n n | |
acc 1] | |
(if (zero? n) | |
acc | |
(recur (dec n) (*' n acc))))) | |
;; Another approach. | |
(defn factorial4 [n] | |
(reduce *' (range 1N (inc n)))) | |
;;;;;;;;;; | |
;;; Functions are values | |
;;;;;;;;;; | |
(defn sum [collection] | |
(reduce + collection)) | |
(defn avg [collection] | |
(/ (sum collection) (count collection))) | |
(defn stats | |
"Takes a collection of numbers and returns a vector with their | |
sum, the number of elements as well as the average value." | |
[numbers] | |
(map #(% numbers) [sum count avg])) | |
(stats [1 2 3]) | |
;;=> [6 3 2] | |
;;;;;;;;;; | |
;;; Magic with map | |
;;;;;;;;;; | |
(reduce (fn [new-map [key val]] | |
(if (> val 4) | |
(assoc new-map key val) | |
new-map)) | |
{} | |
{:human 4.1 | |
:critter 3.9}) | |
;;=> {:human 4.1} | |
;;;;;;;;;; | |
;;; Sequences and collections | |
;;;;;;;;;; | |
;; seq (first, rest, cons). | |
(cons 1 '(2 3)) | |
;;=> (1 2 3) | |
(cons 1 [2 3]) | |
;;=> (1 2 3) | |
;; coll (into, conj). | |
(conj '(2 3) 1) | |
;;=> (1 2 3) | |
(conj [2 3] 1) | |
;;=> [2 3 1] | |
;; Rest parameters (e.g. conj) vs. seqable data structures (e.g. into). | |
(max 1 2 3) | |
;;=> 3 | |
(max [1 2 3]) | |
;;=> [1 2 3] | |
;; "Explode" elements to pass them as separate values. | |
(apply max [1 2 3]) | |
;;=> 3 | |
;; Vice versa. | |
(defn logger [lvl msg] | |
(let [date (new java.util.Date)] | |
(condp = lvl | |
:warning (str "WARNING [" date "]: " msg) | |
:error (str "ERROR [" date "]: " msg)))) | |
(def warn (partial logger :warning)) | |
;;;;;;;;;; | |
;;; Lazy sequences | |
;;;;;;;;;; | |
(def lazy-fib | |
(lazy-cat [0 1] (map + lazy-fib (rest lazy-fib)))) | |
(defn fib [n] | |
((vec (take (inc n) lazy-fib)) n)) | |
(take 10 fibonnaci) | |
;;=> (0 1 1 2 3 5 8 13 21 34) | |
;;;;;;;;;; | |
;;; The power of macros | |
;;;;;;;;;; | |
(defmacro foreach [[sym coll] & body] | |
`(loop [coll# ~coll] | |
(when-let [[~sym & xs#] (seq coll#)] | |
~@body | |
(recur xs#)))) | |
(foreach [x [1 2 3]] (println x)) | |
;;=> 1 | |
;;=> 2 | |
;;=> 3 | |
;;=> nil |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment