Skip to content

Instantly share code, notes, and snippets.

@benzap
Created November 10, 2017 08:40
Show Gist options
  • Save benzap/0ecd35c4da80d750fb746bf6e90ec4eb to your computer and use it in GitHub Desktop.
Save benzap/0ecd35c4da80d750fb746bf6e90ec4eb to your computer and use it in GitHub Desktop.
;; In response to blog post:
;; https://medium.com/@kasperpeulen/10-features-from-various-modern-languages-that-i-would-like-to-see-in-any-programming-language-f2a4a8ee6727
;; Run with lumo
;; https://github.com/anmonteiro/lumo
;;
;; # npm install -g lumo-cljs
;; lumo clojurescript-feature-examples.cljs
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(println "Example #1 - Pipeline Operator")
;;let result = "hello"
;; |> doubleSay
;; |> capitalize
;; |> exclaim;
;; Equivalent in clojure would be threading macros
(defn double-say [x] (str x ", " x))
;; Grab clojure.string/capitalize
(require '[clojure.string :refer [capitalize]])
(defn exclaim [x] (str x "!"))
(def result (-> "hello" double-say capitalize exclaim))
(println "Result:" result)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(println "\nExample 2 - Pattern Matching")
;;let reply =
;; switch message {
;; | "Reason's pretty cool" => "Yep"
;; | "good night" => "See ya!"
;; | "hello" | "hi" | "heya" | "hey" => "hello to you too!"
;; | _ => "Nice to meet you!"
;; };
;; Equivalent in clojure will require the external core.match library
;; However, i'm using lumo-cljs, so i'll have to make due with a
;; purely clojure equivalent
(def message "hi")
(defn reply [message]
(condp contains? message
#{"Reason's pretty cool"} "Yep"
#{"good night"} "See ya!"
#{"hello" "hi" "heya" "hey"} "hello to you too!"
;; else
"Nice to meet you!"
))
(println "Result:" (reply message))
(println "Result 2:" (reply "good night"))
(println "Result 3:" (reply "..."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(println "\nExample 3 - Reactive (Rx) programming built in the language)")
;;input.onKeyDown
;; .where((e) => e.ctrlKey && e.code == 'Enter')
;; .forEach((e) => dispatch(addTodoAction(e.target.value)));
;; The equivalent to this would be watchers on clojure atoms
(def *value (atom 0))
(add-watch *value :value-watcher
(fn [key ref old-state new-state]
(println "*value changed!")
(println "Old Value: " old-state)
(println "New Value: " new-state)
))
(swap! *value inc)
(reset! *value 10)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(println "\nExample 4 - Implicit Name")
;;strings.filter{ it.length == 5 }.map{ it.toUpperCase() }
;; This seems like a pointless feature. Anonymous functions with
;; method dispatch already resolves this.
(require '[clojure.string :refer [upper-case]])
(def strings ["here" "are" "a" "bunch" "of" "interesting" "strings"])
(println "Result:" (->> strings
(filter #(= (count %) 5))
(map upper-case)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(println "\nExample 5 - Destructuring")
;;let someInts = (10, 20);
;;let (ten, twenty) = someInts;
;;type person = {name: string, age: int};
;;let somePerson = {name: "Guy", age: 30};
;;let {name, age} = somePerson;
;; Equivalent is very well supported in clojure. It is probably even
;; more powerful than javascripts implementation
(let [some-ints [10 20]
[ten twenty] some-ints]
(println "Result 1:" ten twenty))
(let [some-person {:name "Guy" :age 30}
{:keys [name age]} some-person]
(println "Result 2:" name age))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(println "\nExample 6 - Cascade Operator")
;;querySelector('#button') // Get an object.
;; ..text = 'Confirm' // Use its members.
;; ..classes.add('important')
;; ..onClick.listen((e) => dispatch(confirmedAction()));
;; When working in clojurescript, you can use the (doto ...) function.
(comment
(doto iframe
(.setAttribute "id" vimeo-iframe-id)
(.setAttribute "src" src)
(.setAttribute "width" "100%")
(.setAttribute "height" "100%")
(.setAttribute "frameborder" "0")
(.setAttribute "webkiteallowfullscreen" true)
(.setAttribute "mozallowfullscreen" true)
(.setAttribute "allowfullscreen" true)))
(println "Example in comments")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(println "\nExample 7 - If expressions")
;;val result = if (param == 1) {
;; "one"
;;} else if (param == 2) {
;; "two"
;;} else {
;; "three"
;;}
;; Equivalent in clojure is cond expressions
(def param 1)
(println "Result:"
(cond
(= param 1) "one"
(= param 2) "two"
:else "three"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(println "\nExample 8 - Try expressions")
;;val result = try {
;; count()
;;} catch (e: ArithmeticException) {
;; throw IllegalStateException(e)
;;}
;; The equivalent in clojure
(println "Result:"
(try (count 0)
(catch js/Object e
(println "Throw Exception")
"Here, have a value")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(println "\nExample 9 - Automatic currying")
;;let add = (x, y) => x + y; /* same as (x) => (y) => x + y; */
;;let five = add(2,3); /* 5 */
;;let alsoFive = add(2)(3); /* 5 */
;;let addFive = add(5); /* y => 5 + y; */
;;let eleven = addFive(6); /* 11 */
;;let twelve = addFive(7); /* 12 */
;; Currying in clojure isn't very well supported, but also not very
;; useful. Some related things in clojure are defining n-arity
;; functions and transducers.
;; Reference: https://clojure.org/reference/transducers
;; The closest example to the above:
(def add (fn [x y] (+ x y)))
(def five (add 2 3))
(def also-five ((partial add 2) 3))
(def add-five (partial add 5))
(def eleven (add-five 6))
(def twelve (add-five 7))
(println "Result:" eleven twelve)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(println "\nExample 10 - Method extensions")
;;public extension Int {
;; func clamp (_ min: Int, _ max: Int) -> Int {
;; return Swift.max(min, Swift.min(max, self))
;; }
;;
;; func abs () -> Int {
;; return Swift.abs(self)
;; }
;;}
;;
;;1.clamp(0, 10); // 1
;;20.clamp(0, 10); // 10
;;-3.abs(); // 3
;; Equivalent in clojure is protocols, which is probably even more powerful
(defprotocol SomeMaths
(clamp [this min max])
(abs [this]))
(extend-protocol SomeMaths
js/Number
(clamp [this min max]
(cond
(> this max) max
(< this min) min
:else this))
(abs [this]
(if (< this 0)
(- this)
this))
js/String
(clamp [this min max]
(let [c (count this)]
(cond
(> c max) (.substr this 0 max)
(< c min) (apply str this (repeat (- max c) "."))
:else this)))
(abs [this] (.toUpperCase this)))
(println "Result(1):" (clamp 23.5 10 20))
(println "Result(2):" (clamp 15 10 20))
(println "Result(3):" (clamp 5 10 20))
(println "Result(4):" (abs -12.5665))
(println "Result(s1):" (clamp "Hellooooooooooaahhh" 5 10))
(println "Result(s2):" (clamp "Hey" 5 10))
(println "Result(s3):" (clamp "Hello" 5 10))
(println "Result(s4):" (abs "Hello"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment