Arity overloading in Clojure source code [duplicate] - clojure

This question already has answers here:
Why clojure's vector function definition is so verbose?
(2 answers)
Closed 5 years ago.
Here's the source code for update-in:
(defn update-in
([m [k & ks] f]
(if ks
(assoc m k (update-in (get m k) ks f))
(assoc m k (f (get m k)))))
([m [k & ks] f a]
(if ks
(assoc m k (update-in (get m k) ks f a))
(assoc m k (f (get m k) a))))
([m [k & ks] f a b]
(if ks
(assoc m k (update-in (get m k) ks f a b))
(assoc m k (f (get m k) a b))))
([m [k & ks] f a b c]
(if ks
(assoc m k (update-in (get m k) ks f a b c))
(assoc m k (f (get m k) a b c))))
([m [k & ks] f a b c & args]
(if ks
(assoc m k (apply update-in (get m k) ks f a b c args))
(assoc m k (apply f (get m k) a b c args)))))
As far as I know (and I don't now much), this always gives the same result:
(defn my-update-in2
([m [k & ks ] f & args]
(if ks
(assoc m k (apply update-in (get m k) ks f args))
(assoc m k (apply f (get m k) args)))))
My question: why isn't update-in (and many other Clojure functions) implemented this way? I would guess there are performance issues, ie. not using apply is faster.

Yes, you have guessed it correctly: some of the arities exist because of the performance cost of apply.
Having explicit arities for the most common cases (e.g. up to 3 arguments to the f function) improves performance as it translates to a direct function call.

Related

Run length encoding of sequences

So I am trying to solve this problem, and this is the code I have come up with:
First I have a pack function, receives a list and groups same elements into a vector.
(defn pack [lst]
(def a [])
(def vect [])
(cond
(empty? lst)
lst
:else
(loop [i 0]
(def r (get lst i))
(def t (get lst (+ i 1)))
(if (= r t)
(def vect (conj vect r))
)
(if (not= r t)
(and (def vect (conj vect r)) (and (def a (conj a vect)) (def vect [])))
)
(if (= i (- (count lst) 1))
a
(recur (inc i))
)
))
)
for example if I have this vector:
(def tes '[a a a a b c c a a d e e e e])
pack function will return this:
[[a a a a] [b] [c c] [a a] [d] [e e e e]]
Then I tried doing the "encode" part of the problem with this code:
(def v1 [])
(def v2 [])
(conj v2 (conj v1 (count (get (pack tes) 0)) (get (get (pack tes) 0) 0)))
And it returned what I wanted, a vector "v2" with a vector "v1" that has the "encoded" item.
[[4 a]]
So now I try to make the function:
(defn encode [lst]
(loop [index 0 limit (count (pack lst)) v1 [] v2[]]
(if (= index limit)
lst
(conj v2 (conj v1 (count (get (pack tes) index)) (get (get (pack tes) index) index)))
)
(recur (inc index) limit v1 v2)
)
)
(encode tes)
but I get this error:
2021/03/07 00:00:21 got exception from server /usr/local/bin/lein: line 152:
28 Killed "$LEIN_JAVA_CMD" "${BOOTCLASSPATH[#]}" -Dfile.encoding=UTF-8 -Dmaven.wagon.http.ssl.easy=false -Dmaven.wagon.rto=10000 $LEIN_JVM_OPTS
-Dleiningen.original.pwd="$ORIGINAL_PWD" -Dleiningen.script="$0" -classpath "$CLASSPATH" clojure.main -m leiningen.core.main "$#"
2021/03/07 01:42:20 error reading from server EOF
Any way to fix my code or to solve the problem more efficiently but still return a vector?
juxt can be used in the pack function:
(defn pack [xs]
(map (juxt count first) (partition-by identity xs)))
(defn unpack [xs]
(mapcat #(apply repeat %) xs))
Don't use def inside function, because it creates global
variable. Use let instead.
Don't use multiple if in row, there is cond.
Format your code better- for example, put all parentheses on the end together on one line.
Here is more efficient solution:
(defn pack [lst]
(letfn [(pack-help [lst]
(if (empty? lst) '()
(let [elem (first lst)]
(cons (vec (take-while #(= % elem) lst))
(pack-help (drop-while #(= % elem) lst))))))]
(vec (pack-help lst))))
(defn pack-with-count [lst]
(mapv #(vector (count %) (first %))
(pack lst)))
(defn unpack [packed-lst]
(into [] (apply concat packed-lst)))
(pack '[a a a a b c c a a d e e e e])
(pack-with-count '[a a a a b c c a a d e e e e])
(unpack '[[a a a a] [b] [c c] [a a] [d] [e e e e]])
As a rule, whenever you reach for loop/recur, there are some pieces of the standard library which will allow you to get the desired effect using higher-order functions. You avoid needing to implement the wiring and can just concentrate on your intent.
(def tes '[a a a a b c c a a d e e e e])
(partition-by identity tes)
; => ((a a a a) (b) (c c) (a a) (d) (e e e e))
(map (juxt count first) *1)
; => ([4 a] [1 b] [2 c] [2 a] [1 d] [4 e])
(mapcat #(apply repeat %) *1)
; => (a a a a b c c a a d e e e e)
Here *1 is just the REPL shorthand for "previous result" - if you need to compose these into functions, this will be replaced with your argument.
If you really need vectors rather than sequences for the outer collection at each stage, you can wrap with vec (to convert the lazy sequence to a vector), or use mapv instead of map.
Finally - the error message you are getting from lein is a syntax error rather than a logic or code problem. Clojure generally flags an unexpected EOF if there aren't enough closing parens.
(println "because we left them open like this -"
Consider working inside a REPL within an IDE, or if that isn't possible then using a text editor that matches parens for you.

How to return a lazy sequence from a loop recur with a conditional in Clojure?

Still very new to Clojure and programming in general so forgive the stupid question.
The problem is:
Find n and k such that the sum of numbers up to n (exclusive) is equal to the sum of numbers from n+1 to k (inclusive).
My solution (which works fine) is to define the following functions:
(defn addd [x] (/ (* x (+ x 1)) 2))
(defn sum-to-n [n] (addd(- n 1)))
(defn sum-to-k [n=1 k=4] (- (addd k) (addd n)))
(defn is-right[n k]
(= (addd (- n 1)) (sum-to-k n k)))
And then run the following loop:
(loop [n 1 k 2]
(cond
(is-right n k) [n k]
(> (sum-to-k n k) (sum-to-n n) )(recur (inc n) k)
:else (recur n (inc k))))
This only returns one answer but if I manually set n and k I can get different values. However, I would like to define a function which returns a lazy sequence of all values so that:
(= [6 8] (take 1 make-seq))
How do I do this as efficiently as possible? I have tried various things but haven't had much luck.
Thanks
:Edit:
I think I came up with a better way of doing it, but its returning 'let should be a vector'. Clojure docs aren't much help...
Heres the new code:
(defn calc-n [n k]
(inc (+ (* 2 k) (* 3 n))))
(defn calc-k [n k]
(inc (+ (* 3 k)(* 4 n))))
(defn f
(let [n 4 k 6]
(recur (calc-n n k) (calc-k n k))))
(take 4 (f))
Yes, you can create a lazy-seq, so that the next iteration will take result of the previous iteration. Here is my suggestion:
(defn cal [n k]
(loop [n n k k]
(cond
(is-right n k) [n k]
(> (sum-to-k n k) (sum-to-n n) )(recur (inc n) k)
:else (recur n (inc k)))))
(defn make-seq [n k]
(if-let [[n1 k1] (cal n k)]
(cons [n1 k1]
(lazy-seq (make-seq (inc n1) (inc k1))))))
(take 5 (make-seq 1 2))
;;=> ([6 8] [35 49] [204 288] [1189 1681] [6930 9800])
just generating lazy seq of candidatess with iterate and then filtering them should probably be what you need:
(def pairs
(->> [1 2]
(iterate (fn [[n k]]
(if (< (sum-to-n n) (sum-n-to-k n k))
[(inc n) k]
[n (inc k)])))
(filter (partial apply is-right))))
user> (take 5 pairs)
;;=> ([6 8] [35 49] [204 288] [1189 1681] [6930 9800])
semantically it is just like manually generating a lazy-seq, and should be as efficient, but this one is probably more idiomatic
If you don't feel like "rolling your own", here is an alternate solution. I also cleaned up the algorithm a bit through renaming/reformating.
The main difference is that you treat your loop-recur as an infinite loop inside of the t/lazy-gen form. When you find a value you want to keep, you use the t/yield expression to create a lazy-sequence of outputs. This structure is the Clojure version of a generator function, just like in Python.
(ns tst.demo.core
(:use tupelo.test )
(:require [tupelo.core :as t] ))
(defn integrate-to [x]
(/ (* x (+ x 1)) 2))
(defn sum-to-n [n]
(integrate-to (- n 1)))
(defn sum-n-to-k [n k]
(- (integrate-to k) (integrate-to n)))
(defn sums-match[n k]
(= (sum-to-n n) (sum-n-to-k n k)))
(defn recur-gen []
(t/lazy-gen
(loop [n 1 k 2]
(when (sums-match n k)
(t/yield [n k]))
(if (< (sum-to-n n) (sum-n-to-k n k))
(recur (inc n) k)
(recur n (inc k))))))
with results:
-------------------------------
Clojure 1.10.1 Java 13
-------------------------------
(take 5 (recur-gen)) => ([6 8] [35 49] [204 288] [1189 1681] [6930 9800])
You can find all of the details in the Tupelo Library.
This first function probably has a better name from math, but I don't know math very well. I'd use inc (increment) instead of (+ ,,, 1), but that's just personal preference.
(defn addd [x]
(/ (* x (inc x)) 2))
I'll slightly clean up the spacing here and use the dec (decrement) function.
(defn sum-to-n [n]
(addd (dec n)))
(defn sum-n-to-k [n k]
(- (addd k) (addd n)))
In some languages predicates, functions that return booleans,
have names like is-odd or is-whatever. In clojure they're usually
called odd? or whatever?.
The question-mark is not syntax, it's just part of the name.
(defn matching-sums? [n k]
(= (addd (dec n)) (sum-n-to-k n k)))
The loop special form is kind of like an anonymous function
for recur to jump back to. If there's no loop form, recur jumps back
to the enclosing function.
Also, dunno what to call this so I'll just call it f.
(defn f [n k]
(cond
(matching-sums? n k) [n k]
(> (sum-n-to-k n k) (sum-to-n n)) (recur (inc n) k)
:else (recur n (inc k))))
(comment
(f 1 2) ;=> [6 8]
(f 7 9) ;=> [35 49]
)
Now, for your actual question. How to make a lazy sequence. You can use the lazy-seq macro, like in minhtuannguyen's answer, but there's an easier, higher level way. Use the iterate function. iterate takes a function and a value and returns an infinite sequence of the value followed by calling the function with the value, followed by calling the function on that value etc.
(defn make-seq [init]
(iterate (fn [n-and-k]
(let [n (first n-and-k)
k (second n-and-k)]
(f (inc n) (inc k))))
init))
(comment
(take 4 (make-seq [1 2])) ;=> ([1 2] [6 8] [35 49] [204 288])
)
That can be simplified a bit by using destructuring in the argument-vector of the anonymous function.
(defn make-seq [init]
(iterate (fn [[n k]]
(f (inc n) (inc k)))
init))
Edit:
About the repeated calculations in f.
By saving the result of the calculations using a let, you can avoid calculating addd multiple times for each number.
(defn f [n k]
(let [to-n (sum-to-n n)
n-to-k (sum-n-to-k n k)]
(cond
(= to-n n-to-k) [n k]
(> n-to-k to-n) (recur (inc n) k)
:else (recur n (inc k)))))

How to use swap to get result in clojure

I want to write the function collect which can combine the sublists into a list, like:
user=> (collect '(a b c d e) 1)
((a)(b)(c)(d)(e))
user=> (collect '(a b c d e) 2)
((a b)(c d)(e))
user=> (collect '(a b c d e) 5)
(a b c d e))
this is my code:
(defn collect [lst num]
(loop [l lst res (atom ())]
(if (<= (count l) num) #res
(recur (drop num l) (swap! res conj (take num (drop num l)))))))
But when I run
user=> (collect '(a b c d e) 1)
I got the error:
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IAtom clojure.core/swap!
why I cannot get the res when I use "swap!" ? Thank you.
It's blowing up in the second pass through the loop.
swap returns the value that was put into the atom, not the atom it's self. So the first pass is updating the atom, and then passing the value it just put into the atom to the second pass through the loop. in the second pass it's trying to use the value as the atom, and getting the exception above.
To "fix" this use a do to update the atom, then pass the atom to the next pass through the loop once it contains the correct value.
user> (defn collect [lst num]
(loop [l lst res (atom ())]
(if (<= (count l) num) #res
(recur (drop num l)
(do (swap! res conj (take num (drop num l)))
res)))))
#'user/collect
user> (collect '(a b c d e) 2)
((e) (c d))
You can also in this case, just remove the atom completely and get exactly the same result (I fixed on ordering problem from your example by using a [] instead of () in the initial value of res):
user> (defn collect [lst num]
(loop [l lst res []]
(if (<= (count l) num) res
(recur (drop num l)
(conj res (take num (drop num l)))))))
#'user/collect
user> (collect '(a b c d e) 2)
[(c d) (e)]
and of course you can also use partition-all as glts mentions above.
;; this would be a correct way to do it
(defn collect [coll n]
(partition-all n coll))
;; this would be a clumsy way to do it
(defn collect
"using a loop (there is not point to do that but at least you can see the logic working as in your example)"
[coll n]
(lazy-seq
(loop [res []
coll coll]
(if (empty? coll)
res
(recur (conj res (take n coll)) (drop n coll))))))
Regarding your error, on the second loop, res is a list-like value, not an atom anymore. That would lead us to :
(defn collect [coll n]
(lazy-seq (loop [res (atom [])
coll coll]
(if (empty? coll)
#res
(recur (do (swap! res conj (take n coll))
;; return the atom instead of the value'
res)
(drop n coll))))))
Note that in order to preserve the order in the solution, I use a vector (litteral []) instead of a list (litteral '()). This is because of the behaviour of conj described here.

if I have the public and private keys of an rsa key, how do I calculate seeds p and q?

This is a repeat of this question: Calculate primes p and q from private exponent (d), public exponent (e) and the modulus (n)
I'm just explicitly stating the problem and asking for a solution - hopefully in clojure:
public key (n):
8251765078168273332294927113607583143463818063169334570141974734622347615608759376136539680924724436167734207457819985975399290886224386172465730576481018297063
private key (d):
3208816897586377860956958931447720469523710321495803767643746679156057326148423456475670861779003305999429436586281847824835615918694834568426186408938023979073
exponent (e): 65537
and I want to get the seeds: p and q
p: 87270901711217520502010198833502882703085386146216514793775433152756453168234183
q: 87270901711217520502010198833502882703085386146216514793775433152756453168234183
To get n and d in the first place is not too hard:
(defn egcd [a b]
(if (= a 0)
[b, 0, 1]
(let [[g y x] (egcd (mod b a) a)]
[g (- x (* y (quot b a))) y])))
(defn modinv [a m]
(let [[g y x] (egcd a m)]
(if (not= 1 g)
(throw (Exception. "Modular Inverse Does Not Exist"))
y)))
(def n (* p q))
(def d (modinv e (* (dec p) (dec q)))
Now I require a reverse transform.
The algorithm Thomas Pornin posted in response to the question you link to works perfectly. Transcribed into Clojure, it looks like this:
;; using math.numeric-tower 0.0.4
(require '[clojure.math.numeric-tower :as num])
(defn find-ks [e d n]
(let [m (num/round (/ (*' e d) n))]
((juxt dec' identity inc') m)))
(defn phi-of-n [e d k]
(/ (dec' (*' e d)) k))
(defn p-and-q [p+q pq]
[(/ (+' p+q (num/sqrt (-' (*' p+q p+q) (*' 4 pq)))) 2)
(/ (-' p+q (num/sqrt (-' (*' p+q p+q) (*' 4 pq)))) 2)])
(defn verify [n p q]
(== n (*' p q)))
(defn solve [e d n]
(first
(for [k (find-ks e d n)
:let [phi (phi-of-n e d k)
p+q (inc' (-' n phi))
[p q] (p-and-q p+q n)]
:when (verify n p q)]
[p q])))
Applying this to your e, d and n we get
(solve 65537N 3208816897586377860956958931447720469523710321495803767643746679156057326148423456475670861779003305999429436586281847824835615918694834568426186408938023979073N 8251765078168273332294927113607583143463818063169334570141974734622347615608759376136539680924724436167734207457819985975399290886224386172465730576481018297063N)
;= [94553452712951836476229946322137980113539561829760409872047377997530344849179361N
87270901711217520502010198833502882703085386146216514793775433152756453168234183N]
You posted the same number as p and q, by the way -- the second one in the result vector above -- but it's easy to verify that these are the correct numbers by using the pair to rederive n and d.

Project Euler #9 (Pythagorean triplets) in Clojure

My answer to this problem feels too much like these solutions in C.
Does anyone have any advice to make this more lispy?
(use 'clojure.test)
(:import 'java.lang.Math)
(with-test
(defn find-triplet-product
([target] (find-triplet-product 1 1 target))
([a b target]
(let [c (Math/sqrt (+ (* a a) (* b b)))]
(let [sum (+ a b c)]
(cond
(> a target) "ERROR"
(= sum target) (reduce * (list a b (int c)))
(> sum target) (recur (inc a) 1 target)
(< sum target) (recur a (inc b) target))))))
(is (= (find-triplet-product 1000) 31875000)))
The clojure-euluer-project has several programs for you to reference.
I personally used this algorithm(which I found described here):
(defn generate-triple [n]
(loop [m (inc n)]
(let [a (- (* m m) (* n n))
b (* 2 (* m n)) c (+ (* m m) (* n n)) sum (+ a b c)]
(if (>= sum 1000)
[a b c sum]
(recur (inc m))))))
Seems to me much less complicated :-)