Problem with writing an infix macro in Clojure - clojure

I'm trying to write a Clojure infix macro, but I get a compilation error which I don't understand.
It should produce function calls from the regular math expression syntax:
(macroexpand '(infix 3 * (2 + 1)))
;; => (* 3 (+ 2 1))
I tried to switch the list statement to a quote, but it didn't work.
The macro:
(defmacro functionize [macro]
`(fn [& args#] (eval (cons '~macro args#))))
(defmacro infix
([n]
(if (not (or (number? n) (fn? n)))
`(~(apply (functionize infix) n))
n))
([fir sec & res]
(list sec (infix fir) (infix res))))
The error:
1. Caused by java.lang.IllegalArgumentException
Don't know how to create ISeq from: clojure.lang.Symbol
The error is for the last line, for the first call for infix.

i can see at least one possible error in your code: [fir sec & res] should probably be [fir sec res], since you need the third arg, not the list of all args. It still doesn't fix the problems in your code. The main one, is that you are overthinking it (with eval and stuff)
I would probably use something like this:
(defmacro infix [n]
(if (list? n)
(let [[arg1 op arg2] n]
`(~op (infix ~arg1) (infix ~arg2)))
n))
user> (clojure.walk/macroexpand-all '(infix (1 + ((6 - (3 / 7)) * 3))))
;;=> (+ 1 (* (- 6 (/ 3 7)) 3))
user> (infix (1 + ((6 - (3 / 7)) * 3)))
;;=> 124/7
UPDATE
to omit parentheses you could update it this way:
(defn unwrap-arg [restargs]
(if (= 1 (count restargs))
(first restargs)
restargs))
(defmacro infix [n]
(if (list? n)
(let [[arg1 op & arg2] n]
`(~op (infix ~arg1) (infix ~(unwrap-arg arg2))))
n))
user> (clojure.walk/macroexpand-all '(infix (1 + 2 + (10 - (4 / 10)) + (4 * 5))))
;;=> (+ 1 (+ 2 (+ (- 10 (/ 4 10)) (* 4 5))))
user> (infix (1 + 2 + (10 - (4 / 10)) + (4 * 5)))
;;=> 163/5

Related

Clojure - using map recursively

If I have a list, I can use map to apply a function to each item of the list.
(map sqrt (list 1 4 9))
(1 2 3)
I can also use map in front of a list of lists:
(map count (list (list 1 2 3) (list 4 5)))
(4 5)
Now is there a way to apply sqrt to each number in the list of lists? I want to start from
(list (list 1 4 9) (list 16 25))
and obtain
((1 2 3)(4 5))
However, the following does not seem to work,
(map (map sqrt) (list (list 1 4 9) (list 16 25)))
nor the following.
(map (fn [x] (map sqrt x)) (list (list 1 4 9) (list 16 25)))
Why? (And how do I solve this?)
Your second to last version "nearly" works. Clojure has no automatic
currying, so (map sqrt) is not partial application, but (map sqrt)
returns a transducer, which takes one argument and returns a function
with three different arities - so running your code there will give you
back a function for each list of numbers.
To make that work, you can use partial:
user=> (map (partial map sqrt) (list (list 1 4 9) (list 16 25)))
((1 2 3) (4 5))
And of course there is the obligatory specter answer:
user=> (transform [ALL ALL] sqrt '((1 4 9)(16 25)))
((1 2 3) (4 5))
You can write recursive function for this task:
(defn deep-map [f seq1]
(cond (empty? seq1) nil
(sequential? (first seq1))
(cons (deep-map f (first seq1))
(deep-map f (rest seq1)))
:else (cons (f (first seq1))
(deep-map f (rest seq1)))))
Example:
(deep-map #(Math/sqrt %) '((1 4 9) (16 25 36)))
=> ((1.0 2.0 3.0) (4.0 5.0 6.0))
Or you can use clojure.walk and function postwalk:
(clojure.walk/postwalk
#(if (number? %) (Math/sqrt %) %)
'((1 4 9) (16 25 36)))
=> ((1.0 2.0 3.0) (4.0 5.0 6.0))
The function map is closely related to the function for, which I think is sometimes easier to use. Here is how I would solve this problem:
(let [matrix [[1 4 9]
[16 25]]
result (vec (for [row matrix]
(vec (for [num row]
(Math/sqrt num)))))]
result)
with result:
result =>
[[1.0 2.0 3.0]
[4.0 5.0]]
If you remove the two (vec ...) bits, you'll see the same result but for normally returns a lazy sequence.
#MartinPuda's answer is right.
The tail call recursive version is here:
(defn map* [f sq & {:keys [acc] :or {acc '()}}]
(cond (empty? sq) (vec (reverse acc))
(sequential? (first sq)) (map* f
(rest sq)
:acc (cons (map* f (first sq)) acc))
:else (map* f (rest sq) :acc (cons (f (first sq)) acc))))
By tradition in lisp, such recursively into the nested structure going functions are fnname* (marked by an asterisk at the end).
acc accumulates the result nested tree which is constructed by cons.
In your case this would be:
(map* Math/sqrt (list (list 1 4 9) (list 16 25)))
Test with:
(map* (partial + 1) '[1 2 [3 4 [5] 6] 7 [8 [9]]])
;; => [2 3 [4 5 [6] 7] 8 [9 [10]]]

Mysterious Clojure function

I would like to write a clojure function that has the following behaviour :
(take 4 (floyd))
=> '((1) (2 3) (4 5 6) (7 8 9 10))
(take 3 (floyd))
=> '((1) (2 3) (4 5 6))
(take 1 (floyd))
=> '((1)))
I tried using partition and partition-all to validate these tests however i couldn't get the right solution. If you have any idea of how to do it, i would really appreciate a little help. I started using clojure a few weeks ago and still have some issues.
Thanks
Here's another option:
(defn floyd []
(map (fn [lo n] (range lo (+ lo n 1)))
(reductions + 1 (iterate inc 1))
(range)))
(take 5 (floyd))
;=> ((1) (2 3) (4 5 6) (7 8 9 10) (11 12 13 14 15))
This was arrived at based on the observation that you want a series of increasing ranges (the (range) argument to map is used to produce a sequence of increasingly longer ranges), each one starting from almost the triangular number sequence:
(take 5 (reductions + 0 (iterate inc 1)))
;=> (0 1 3 6 10)
If we start that sequence from 1 instead, we get the starting numbers in your desired sequence:
(take 5 (reductions + 1 (iterate inc 1)))
;=> (1 2 4 7 11)
If the + 1 inside the mapped function bothers you, you could do this instead:
(defn floyd []
(map (fn [lo n] (range lo (+ lo n)))
(reductions + 1 (iterate inc 1))
(iterate inc 1)))
it is not possible to solve it with partition / partition-all, since they split your sequence into predefined size chunks.
What you can do, is to employ recursive lazy function for that:
user> (defn floyd []
(letfn [(f [n rng]
(cons (take n rng)
(lazy-seq (f (inc n) (drop n rng)))))]
(f 1 (iterate inc 1))))
#'user/floyd
user> (take 1 (floyd))
;;=> ((1))
user> (take 2 (floyd))
;;=> ((1) (2 3))
user> (take 3 (floyd))
;;=> ((1) (2 3) (4 5 6))
user> (take 4 (floyd))
;;=> ((1) (2 3) (4 5 6) (7 8 9 10))
another variant can use similar approach, but only track chunk-start/chunk-size:
user> (defn floyd []
(letfn [(f [n start]
(cons (range start (+ start n))
(lazy-seq (f (inc n) (+ start n)))))]
(f 1 1)))
another approach is to use clojure's collection operating functions:
user> (defn floyd-2 []
(->> [1 1]
(iterate (fn [[start n]]
[(+ n start) (inc n)]))
(map (fn [[start n]] (range start (+ start n))))))
#'user/floyd-2
user> (take 4 (floyd-2))
;;=> ((1) (2 3) (4 5 6) (7 8 9 10))
user> (take 5 (floyd-2))
;;=> ((1) (2 3) (4 5 6) (7 8 9 10) (11 12 13 14 15))
user> (take 1 (floyd-2))
;;=> ((1))
How about this:
(defn floyd []
(map (fn[n]
(let [start (/ (* n (inc n)) 2)]
(range (inc start) (+ start n 2))))
(iterate inc 0)))
(take 4 (floyd))

Getting the most nested list in Clojure

I am migrating some LISP functions to Clojure. I have problems with StackOverflow message for the following functions:
(defn m
[list depth]
(cond
(= list nil) depth
(atom (first list)) (m (rest list) depth)
(> (m (first list) (+ depth 1)) (m (rest list) depth)) (m (first list) (+ depth 1))
:default (m (rest list) depth))
)
(defn n
[list depth maxdepth]
(cond
(= list nil) nil
(= depth maxdepth) list
(atom (first list)) (n (rest list) depth maxdepth)
(= 0 (n (first list) (+ depth 1) maxdepth)) (n (last list) depth maxdepth)
:default (n (first list) (+ depth 1) maxdepth))
)
(defn myfind[mylist]
(n mylist 0 (m mylist 0))
)
What I basically want is the output of the most nested list, as in:
(myfind '(1 2 3 (4 5) 6 ((7 8) 9)))
=> (7 8)
The goal is to use recursion and minimize the usage of builtin functions to achieve that.
What is wrong in this case?
(defn- deepest-with-depth [depth s]
(let [nested-colls (filter coll? s)]
(if (seq nested-colls)
(mapcat (partial deepest-with-depth (inc depth)) nested-colls)
[[depth s]])))
(defn deepest [s]
(->> (deepest-with-depth 0 s)
(apply max-key first)
second))
> (deepest '(1 2 3 (4 5) 6 ((7 8) 9)))
(7 8)
Feel free to subsitute some function calls (e.g. max-key, partial) with their implementations, if they conflict with your requirements.
here is one more variant, with just classic old school solution, and no clojure specific sequence functions at all:
(defn deepest [items depth]
(if (sequential? items)
(let [[it1 d1 :as res1] (deepest (first items) (inc depth))
[it2 d2 :as res2] (deepest (next items) depth)]
(cond (>= depth (max d1 d2)) [items depth]
(>= d1 d2) res1
:else res2))
[items -1]))
it is also notable by it's classic approach to the nested lists recursion: first you recur on car, then on cdr, and then combine these results.
user> (deepest '(1 2 3 (4 5) 6 ((7 8) 9)) 0)
[(7 8) 2]
user> (deepest '(1 2 3 (4 5) 6) 0)
[(4 5) 1]
user> (deepest '(1 2 3 (x ((y (z)))) (4 5) 6) 0)
[(z) 4]
user> (deepest '(1 2 3 (x ((y (z)))) (4 5 ((((((:xxx)))))))) 0)
[(:xxx) 7]
user> (deepest '(1 2 3 ((((((((nil)))))))) (x ((y (z)))) (4 5) 6) 0)
[(nil) 8]
user> (deepest '(1 2 3) 0)
[(1 2 3) 0]
(defn- max-depth-entry [a-list]
(let [sub-lists (filter coll? a-list)
[depth list] (if (empty? sub-lists)
[0 a-list]
(apply max-key first (map max-depth-entry sub-lists)))]
[(inc depth) list]))
(max-depth-entry '(1 2 3 (4 5) 6 ((7 8) 9)))
;[3 (7 8)]
Then
(def max-depth-sublist (comp second max-depth-entry))
(max-depth-sublist '(1 2 3 (4 5) 6 ((7 8) 9)))
;(7 8)
I owe the idea of using max-key to OlegTheCat's answer. I originally knitted my own, using reduce:
(defn- max-depth-entry [a-list]
(let [sub-lists (filter coll? a-list)
[a-list a-depth] (reduce
(fn ([] [a-list 0])
([[as an :as asn] [s n :as sn]] (if (> n an) sn asn)))
(map max-depth-entry sub-lists))]
[a-list (inc a-depth)]))
Then
(def max-depth-sublist (comp first max-depth-entry))
Now I'm ready to return to Sequs Horribilis on 4Clojure, which has stymied me until now.

find all ordered triples of distinct positive integers i, j, and k less than or equal to a given integer n that sum to a given integer s

this is the exercise 2.41 in SICP
I have wrote this naive version myself:
(defn sum-three [n s]
(for [i (range n)
j (range n)
k (range n)
:when (and (= s (+ i j k))
(< 1 k j i n))]
[i j k]))
The question is: is this considered idiomatic in clojure? And how can I optimize this piece of code? since it takes forever to compute(sum-three 500 500)
Also, how can I have this function take an extra argument to specify number of integer to compute the sum? So instead of sum of three, It should handle more general case like sum of two, sum of four or sum of five etc.
I suppose this cannot be achieved by using for loop? not sure how to add i j k binding dynamically.
(Update: The fully optimized version is sum-c-opt at the bottom.)
I'd say it is idiomatic, if not the fastest way to do it while staying idiomatic. Well, perhaps using == in place of = when the inputs are known to be numbers would be more idiomatic (NB. these are not entirely equivalent on numbers; it doesn't matter here though.)
As a first optimization pass, you could start the ranges higher up and replace = with the number-specific ==:
(defn sum-three [n s]
(for [k (range n)
j (range (inc k) n)
i (range (inc j) n)
:when (== s (+ i j k))]
[i j k]))
(Changed ordering of the bindings since you want the smallest number last.)
As for making the number of integers a parameter, here's one approach:
(defn sum-c [c n s]
(letfn [(go [c n s b]
(if (zero? c)
[[]]
(for [i (range b n)
is (go (dec c) n (- s i) (inc i))
:when (== s (apply + i is))]
(conj is i))))]
(go c n s 0)))
;; from the REPL:
user=> (sum-c 3 6 10)
([5 4 1] [5 3 2])
user=> (sum-c 3 7 10)
([6 4 0] [6 3 1] [5 4 1] [5 3 2])
Update: Rather spoils the exercise to use it, but math.combinatorics provides a combinations function which is tailor-made to solve this problem:
(require '[clojure.math.combinatorics :as c])
(c/combinations (range 10) 3)
;=> all combinations of 3 distinct numbers less than 10;
; will be returned as lists, but in fact will also be distinct
; as sets, so no (0 1 2) / (2 1 0) "duplicates modulo ordering";
; it also so happens that the individual lists will maintain the
; relative ordering of elements from the input, although the docs
; don't guarantee this
filter the output appropriately.
A further update: Thinking through the way sum-c above works gives one a further optimization idea. The point of the inner go function inside sum-c was to produce a seq of tuples summing up to a certain target value (its initial target minus the value of i at the current iteration in the for comprehension); yet we still validate the sums of the tuples returned from the recursive calls to go as if we were unsure whether they actually do their job.
Instead, we can make sure that the tuples produced are the correct ones by construction:
(defn sum-c-opt [c n s]
(let [m (max 0 (- s (* (dec c) (dec n))))]
(if (>= m n)
()
(letfn [(go [c s t]
(if (zero? c)
(list t)
(mapcat #(go (dec c) (- s %) (conj t %))
(range (max (inc (peek t))
(- s (* (dec c) (dec n))))
(min n (inc s))))))]
(mapcat #(go (dec c) (- s %) (list %)) (range m n))))))
This version returns the tuples as lists so as to preserve the expected ordering of results while maintaining code structure which is natural given this approach. You can convert them to vectors with a map vec pass.
For small values of the arguments, this will actually be slower than sum-c, but for larger values, it is much faster:
user> (time (last (sum-c-opt 3 500 500)))
"Elapsed time: 88.110716 msecs"
(168 167 165)
user> (time (last (sum-c 3 500 500)))
"Elapsed time: 13792.312323 msecs"
[168 167 165]
And just for added assurance that it does the same thing (beyond inductively proving correctness in both cases):
; NB. this illustrates Clojure's notion of equality as applied
; to vectors and lists
user> (= (sum-c 3 100 100) (sum-c-opt 3 100 100))
true
user> (= (sum-c 4 50 50) (sum-c-opt 4 50 50))
true
for is a macro so it's hard to extend your nice idiomatic answer to cover the general case. Fortunately clojure.math.combinatorics provides the cartesian-product function that will produce all the combinations of the sets of numbers. Which reduces the problem to filter the combinations:
(ns hello.core
(:require [clojure.math.combinatorics :as combo]))
(defn sum-three [n s i]
(filter #(= s (reduce + %))
(apply combo/cartesian-product (repeat i (range 1 (inc n))))))
hello.core> (sum-three 7 10 3)
((1 2 7) (1 3 6) (1 4 5) (1 5 4) (1 6 3) (1 7 2) (2 1 7)
(2 2 6) (2 3 5) (2 4 4) (2 5 3) (2 6 2) (2 7 1) (3 1 6)
(3 2 5) (3 3 4) (3 4 3) (3 5 2) (3 6 1) (4 1 5) (4 2 4)
(4 3 3) (4 4 2) (4 5 1) (5 1 4) (5 2 3) (5 3 2) (5 4 1)
(6 1 3) (6 2 2) (6 3 1) (7 1 2) (7 2 1))
assuming that order matters in the answers that is
For making your existing code parameterized you can use reduce.This code shows a pattern that can be used where you want to paramterize the number of cases of a for macro usage.
Your code without using for macro (using only functions) would be:
(defn sum-three [n s]
(mapcat (fn [i]
(mapcat (fn [j]
(filter (fn [[i j k]]
(and (= s (+ i j k))
(< 1 k j i n)))
(map (fn [k] [i j k]) (range n))))
(range n)))
(range n)))
The pattern is visible, there is inner most map which is covered by outer mapcat and so on and you want to paramterize the nesting level, hence:
(defn sum-c [c n s]
((reduce (fn [s _]
(fn [& i] (mapcat #(apply s (concat i [%])) (range n))))
(fn [& i] (filter #(and (= s (apply + %))
(apply < 1 (reverse %)))
(map #(concat i [%]) (range n))))
(range (dec c)))))

Lazy Pascal's Triangle in Clojure

I'm trying to write a succinct, lazy Pascal's Triangle in Clojure, rotated such that the rows/columns follow the diagonals of the triangle. That is, I want to produce the following lazy-seq of lazy-seqs:
((1 1 1 1 ...)
(1 2 3 4 ...)
(1 3 6 10 ...)
...
)
The code I have written is:
(def pascal
(cons (repeat 1)
(lazy-seq
(map #(map + %1 %2)
(map #(cons 0 %) (rest pascal)))
pascal
)))
so that each row is formed by adding a right-shifted version of itself to the previous row. The problem is that it never gets past the first line, since at that point (map #(cons 0 %) (rest pascal))) is empty.
=> (take 5 (map #(take 5 %) pascal))
((1 1 1 1 1))
What's a sensible way to go about solving this? I'm fairly new to programming in Clojure, and the very different way of thinking about a problem that it involves, so I'd really appreciate suggestions from anybody more experienced with this.
Succinct and lazy
(def pascal (iterate (partial reductions +') (repeat 1)))
(map (partial take 5) (take 5 pascal))
;=> ((1 1 1 1 1)
; (1 2 3 4 5)
; (1 3 6 10 15)
; (1 4 10 20 35)
; (1 5 15 35 70))
But too lazy?
(take 5 (nth pascal 10000))
;=> StackOverflowError
Try again
(take 5 (nth pascal 10000))
;=> (0)
Uh-oh, start over, and try, try again
(def pascal (iterate (partial reductions +') (repeat 1)))
(count (flatten (map (partial take 5) (take 100000 pascal))))
;=> 500000
Now these are all in your heap
(take 5 (nth pascal 100000))
;=> (1 100001 5000150001 166676666850001 4167083347916875001)
pascal should not be a var but a function that generates infinite seqs.
Check out this question for usage on lazy-seq
BTW, try this:
(defn gennext [s sum]
(let [newsum (+ (first s) sum)]
(cons newsum
(lazy-seq (gennext (rest s) newsum)))))
(defn pascal [s]
(cons s
(lazy-seq (pascal (gennext s 0)))))
(pascal (repeat 1)) gives you integer overflow exception but that does mean it produces the infinite seqs. You can use +' to use big integer.