Created
November 10, 2017 08:40
-
-
Save benzap/0ecd35c4da80d750fb746bf6e90ec4eb 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
;; 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