Here’s how you can zip up multiple lists into a single list of pairs or tuples using
(map vector ).
(def letters [:a :b :c])
(def numbers [1 2 3])
(def fruits ["peach" "tomato" "orange"])
(map vector letters numbers)
; => ([:a 1] [:b 2] [:c 3])
(map vector letters fruits numbers)
; => ([:a "peach" 1] [:b "tomato" 2] [:c "orange" 3])
Cool trick, but how is this useful, you ask?
Continue reading “Combining lists into tuples”
Here’s some code that maps a score to a grade.
(<= 80 grade) "A"
((and (<= 70 grade) (> grade 80)) "B"
((and (<= 60 grade) (> grade 70)) "C"
((and (<= 50 grade) (> grade 60)) "D"
((and (<= 40 grade) (> grade 50)) "E"
(> 40 grade) "F"))
A nicer way with currying.
(defn between? [low high]
(and (<= low score) (> high score)))
(<= 80 grade) "A"
((between? 70 80) grade) "B"
((between? 60 70) grade) "C"
((between? 50 60) grade) "D"
((between? 40 50) grade) "E"
(> 40 grade) "F"))
between? takes the
high parameters, and returns a function
(fn [score] ) that checks if
score is between
Nested functions can get unwieldly:
(not (nil? name))
((comp not nil?) name)
((complement nil?) name)
Better, extend the language for yourself:
(defn not-nil? [v] (not (nil? v)))
When a dog owner wants to train his dog, the procedure is well-known and quite simple. The owner runs two loops: one of positive feedback and one of negative ditto. Whenever the dog does something right, the positive feedback loop is invoked and the dog is treated with a snack. Whenever the dog does something wrong, the dog is scolded and the negative feedback loop is used.
The result is positive and negative reinforcement of the dogs behavior. The dog will over time automatically behave as the owner wants and never even think of misbehaving
When a programming language trains its leashed programmer, it likewise uses positive and negative feedback. Whenever a problem is easily solvable in the constructs and features of said language, it reinforces the use of those features and constructs. And also in the same vein, if something is hard to do in the language, the programmer will shy away from thinking the idea, since it may be too hard to do in the language. Another negative feedback loop is when resource usage of a program is bad. Either it will use too much memory of too many CPU resources to carry out its work. This discourages the programmer from using that solution again.
The important point is that while all practical general purpose languages are Turing complete, the way they train programmers to behave as they want is quite different. In an Object Oriented language for instance, the programmer is trained to reframe most – if not all – questions as objects of bundled fields and methods. A functional programmer is trained to envision programs as transformations of data from the form X into the form Y through the application of a function. And so on.
(excerpt from One major difference – ZeroMQ and Erlang by Jesper Louis Andersen)
While I wouldn’t readily admit to the pertinence of comparing a programming language to a canine owner in the way they interact with their primary subjects, the principle of positive and negative feedback loops extend beyond programming languages to the IDE‘s and platforms that we develop on. Beyond the industry, it is embedded in every tool and device we come in contact with, chipping away at every facet of daily life as we know it.
This is why I’ve spent significant pockets of my two week holiday wrapping my mind around the LISP-y Clojure and forcing myself to do it in Emacs (non-trivial, coming from many years of vimming). From the point of view of the final product, I’m hard pressed to point out any significant differences, i.e. It doesn’t matter what editor you use, or what language you code in; but from a educational and developmental angle, the benefits are rife and immense.
I’ve been trying to pick up Clojure. My key motivating factor is the hope of one day being able to appreciate the gravity of the LISP family of languages, unveil the power behind S-expressions, dabble with the somewhat black art of concurrency and functional programming.
Thus far, it’s taken me the earlier half of 3 books on Clojure to get to this point where I’m relatively comfortable with the syntax and some of the idioms of the language. But because of its terseness, Clojure doesn’t afford a newbie very much “typing time” to digest and soak in the language. In Clojure, you start your first paren, and before you know it, you’ve executed the code in the REPL successfully – no mistakes to learn from, no cryptic error messages to keep in mind.
I’ve recently picked up a book called Programming Intelligence. It’s a book about data mining, machine learning and other meaty AI stuff with all its code samples in Python.
So what I’ve been doing as my latest stage in Clojure learning, is going through the book, digesting the Python code samples, and reimplementing them in Clojure.
Here’s an example of a snippet in Python:
And my version in Clojure:
I’ve only done about 3 snippets so far, but I feel like I’ve learned a lot because I haven’t simply copied code out of a book (which hasn’t really worked for reasons stated above), nor have I had to “come up” with things to implement. By reimplementing code from another language in Clojure, I get to practice the syntax while copying the algorithms.