Posts Tagged by Clojure
4Clojure 59 Juxtaposition
| 16-Jul-2012 | Posted by Sonia Hamilton under Clojure |
4clojure problem 59 Juxtapostion – here’s how I approached the problem (warts and all) in the hope that it helps others who are learning Clojure.
A reminder of what the juxt function does:
Takes a set of functions and returns a fn that is the juxtaposition of those fns. The returned fn takes a variable number of args, and returns a vector containing the result of applying each fn to the args (left-to-right). ((juxt a b c) x) => [(a x) (b x) (c x)]
The problem was fairly easy, it just required the HOF (Higher Order Functions) abstraction of thinking of functions as arguments, like any other (numeric, string, …) argument.
First of all, I need a function that takes a variable number of arguments (0-n) – standard destructuring:
(defn myjuxt [& fs] ...
I don’t know what to do with these functions yet, so I’ll just loop through using for and return each function:
(defn myjuxt [& fs] (for [f fs] f))
And here you can see the returned list of function objects. Not very useful but a start:
(myjuxt + min max) user => (#core_plus #core_min #core_max)
The question gives a good hint here: “return a new function that takes a variable number of arguments”. So do that, using the same destructuring approach for a variable number of arguments:
(defn myjuxt2 [& fs] (fn [& xs] ...
So I want to run each function against these arguments, so I’ll use for again:
(defn myjuxt2 [& fs] (ƒ [& xs] (for [f fs] (f xs)))) ((myjuxt2 + min max) 1 2 3) user=> (ClassCastException Cannot cast clojure.lang.ArraySeq to java.lang.Number
Ouch! But the error message gives a hint – something is seeing an array instead of a number. My three functions want numbers and they’re getting arrays – I need apply to “strip out” the arguments:
(defn myjuxt2 [& fs] (fn [& xs] (for [f fs] (apply f xs)))) ((myjuxt2 + min max) 1 2 3) user=> (6 1 3)
And it works! Looking at the solutions I see that I could’ve used map instead of for, and #() instead of (fn), but they’re minor “golfing” details.
4clojure 100 Least Common Multiple
| 06-Jul-2012 | Posted by Sonia Hamilton under Clojure |
4clojure problem 100 – calculate the Least Common Multiple (LCM) of two or more numbers.
![]()
Here’s how I worked it out in the REPL, warts and all….
I first thought about using the meaning of LCM to solve this (as given in Wikipedia), ie for two numbers a and b (eg 4 and 6), find all the multiples of a (an infinite sequence), find all the multiples of b (an infinite sequence), and find the first match. But I was impatient and didn’t want to work out how to find the first match between lists, so I decided to use the GCD definition:
![]()
From there it was just a matter of balancing parentheses (thanks paredit) by breaking up the problem into stages, starting with calculating the GCD of two numbers:
(defn gcd [a b] (cond (= b 0) a (= a 0) b (> a b) (gcd b (mod a b)) (> b a) (gcd a (mod b a)))) (gcd 15 5) ==> 5
Now get LCM working for two arguments:
(defn lcm [x y] (/ (* x y) (gcd x y))) (lcm 4 6) ==> 12
Now get LCM working for more than two arguments. I remembered seeing multiple arities used to solve other 4clojure problems, so I thought I’d use the Arity-Reduce “pattern” (well I’m using apply, same idea):
(defn lcm2 ([x y] (/ (* x y) (gcd x y))) ([x y & rest] (apply lcm2 (lcm2 x y) rest))) (lcm2 5 3 7) ==> 105
4clojure doesn’t allow defn, so I then used letfn to nest my definition of GCD inside LCM:
(fn lcm3
([x y]
(letfn [(gcd2 [a b]
(cond
(= b 0) a
(> a b) (gcd2 b (mod a b))
(> b a) (gcd2 a (mod b a))))]
(/ (* x y) (gcd2 x y))))
([x y & rest] (apply lcm3 (lcm3 x y) rest)))
(lcm3 5 3 7)
==> 105
So my solution worked, but it wasn’t very elegant – Dacquiri wins the prize for that, again :-)
4clojure 97 Pascal’s Triangle
| 04-Jun-2012 | Posted by Sonia Hamilton under Clojure |
4clojure problem 97 Pascal’s Triangle – calculate the nth row:
![]()
My solution:
(defn pascal [n]
(if (= n 1)
[1]
(map #(apply + %)
(partition 2 1
(concat [0] (pascal (- n 1)) [0])))))
(pascal 5)
user=> (1 4 6 4 1)
A negative – my solution doesn’t use tail recursion; on my laptop it works up to about n = 760:
(pascal 10e4) user=> java.lang.StackOverflowError (NO_SOURCE_FILE:0)
4clojure 63 Group a Sequence
| 04-Jun-2012 | Posted by Sonia Hamilton under Clojure |
My first attempt at writing up one of my 4clojure solutions. Problem 63 “Group a Sequence” requires you to re-implement group-by. As always looking at the source code is cheating :-)
Given a function f and a sequence s, write a function which returns a map. The keys should be the values of f applied to each item in s. The value at each key should be a vector of corresponding items in the order they appear in s.
(= (__ #(> % 5) [1 3 6 8]) {false [1 3], true [6 8]})
Here’s how I worked it out in the REPL, warts and all…
;; map seems a good start here
((map #(> % 5) [1 3 6 8]) ;; (false false true true)
;; so I’m getting the values of fn here, I want the inputs too
;; I can’t think of a clever way to do this, I’ll just use for and list
(defn foo [f xs] (for [x xs :let [y (f x)]] (list y x))) (foo #(> % 5) [1 3 6 8]) ;; ((false 1) (false 3) (true 6) (true 8))
;; the for loop can be tightend up, I don’t need the :let
(defn foo [f xs] (for [x xs] (list (f x) x))) (foo #(> % 5) [1 3 6 8]) ;; ((false 1) (false 3) (true 6) (true 8))
;; I know I want my results as maps, so use a map instead
(defn foo [f xs] (for [x xs] {(f x) x}))
(foo #(> % 5) [1 3 6 8])
;; ({false 1} {false 3} {true 6} {true 8})
;; now I’m stuck; how do I moosh the results together?
;; I read thru all the map change fn’s in the clj cheatsheet
;; hmmm, merge-with looks promising
(defn foo [f xs] (merge-with concat (for [x xs] {(f x) x})))
(foo #(> % 5) [1 3 6 8])
;; ({false 1} {false 3} {true 6} {true 8})
;; WTF? same results. Re-RTFM on merge-with. Well, I’m going to
;; need vectors in my results to be able to concat them…
(defn foo [f xs] (merge-with concat (for [x xs] {(f x) [x]})))
(foo #(> % 5) [1 3 6 8])
;; ({false [1]} {false [3]} {true [6]} {true [8]})
;; WTF? still not mooshing together. Uh duh, fn signature takes
;; “maps” not a list. Use the “list stripper” – apply!
(defn foo [f xs] (apply merge-with concat (for [x xs] {(f x) [x]})))
(foo #(> % 5) [1 3 6 8])
;; {true (6 8), false (1 3)}
;; ha, sweetness and light! Remove the defn and submit:
(fn [f xs] (apply merge-with concat (for [x xs] {(f x) [x]})))
;; look at other’s solutions. Dacquiri as usual has a more elegant
;; solution, with a reader macro. What’s his golf handicap?!?!
#(apply merge-with concat (for [x %2] {(% x) [x]}))
Mooshing is an advanced programming technique, that can only be used after years of study and practice…
Emacs Paredit Notes for OSX
| 02-Jun-2012 | Posted by Sonia Hamilton under Clojure, Emacs |
Some notes on Emacs’ Paredit mode. More so I can stop fighting with Paredit and do some Clojure programming than show any expertise – see Mudphone’s Paredit Preso for the real deal, as well as hagelb’s Paredit screencast notes and the Paredit Cheat Sheet.
- M-( wrap parens around something. Also for { [ “
- M-s remove parens from something
- M-S-s split sexpr into two
- M-S-j join sexprs
- C-q ♦ just do what I say, dammit! force insert of paren or bracket ♦
- C-u DEL force delete paren or bracket
“Barfage and slurpage” ie moving parens left and right. I had some trouble getting this going on OSX, as the terminal doesn’t seem to map control key sequences correctly. After modifying emacs (see below), I got these going:
- C-<right>, C-<left> move right paren right or left
- ESC C-<right>, ESC C-<left> move left paren right or left
I wrote this elisp for my ~/.emacs.d/sonia.el (I’m using Technomancy’s Emacs Starter Kit):
(when (eq system-type 'darwin)
(eval-after-load 'paredit
'(progn
;; C-left
(define-key paredit-mode-map (kbd "M-[ 5 d")
'paredit-forward-barf-sexp)
;; C-right
(define-key paredit-mode-map (kbd "M-[ 5 c")
'paredit-forward-slurp-sexp)
;; ESC-C-left
(define-key paredit-mode-map (kbd "ESC M-[ 5 d")
'paredit-backward-slurp-sexp)
;; ESC-C-right
(define-key paredit-mode-map (kbd "ESC M-[ 5 c")
'paredit-backward-barf-sexp)
)))

Recent Comments
<<EOF>>was eaten...cat <>~/.vi...