Clojure: Implementing the some function - clojure

I'm new to clojure and tried to implement the some function (for some specific tests):
(my-some even? [1 2 3 4]) => true
(my-some #{3 4} [1 2 3 4]) => 3
(my-some zero? [1 2 3 4]) => nil
That's what I came up with so far:
(defn my-some [f x]
(loop [[y & t] x]
(if (empty? t) nil
(if (f y)
(f y)
(recur t)))))
I could imagine there are more idiomatic approaches.
Any suggestions?

Firstly, you have a bug: [[y & t] x] destructures x, but the following empty? check on t means you are ignoring the last element in the sequence. You can see this with
(my-some even? [2])
=> nil
You can replace (if (empty? x) nil (else-form)) with when and seq:
(when (seq x) ...)
you can then use first and next to deconstruct the sequence:
(defn my-some [f x]
(when (seq x)
(if (f (first x))
(f (first x))
(recur f (rest x)))))
the call to recur is then back into my-some so you need to pass the predicate f.
you can replace (if x x (else ....)) with (or x (else ...)):
(defn my-some [f x]
(when (seq x)
(or (f (first x)) (recur f (next x)))))
you can compare this with the implementation of some

Related

Why does a StackOverflowError occur only when function doesn't use sequence destructing?

The following code was run on the 4closure site for problem 19.
The function I was writing was supposed to return the last element in a sequence.
A java.lang.StackOverflowError occurred for this definition:
(fn my-last [lst]
(if (rest lst)
(my-last (rest lst))
(first lst)))
But when I ran the following definition it worked fine:
(fn my-last [[x & xs]]
(if xs
(my-last xs)
x))
The only difference in the two blocks above seems to be the destructive sequence binding use of destructuring in the parameter list.
So how come the first definition throws an error?
And are there any differences between the two functions that I am missing?
Edit: fixed typo in first function definition
Here is the answer:
(rest [1 2 3]) => (2 3)
(rest [3]) => ()
(next [3]) => nil
Using rest returns the empty sequence (), which evaluates to true in your test. Using next returns nil when there are no more items. Since Clojure considers nil the same as false, this will make it work.
Since many people get tripped up on this point, I would prefer a more explicit test, such as this:
(if-not (empty? ...))
or similar.
Update:
Here is how I would write it. The testing stuff is from the Tupelo library.
(ns tst.demo.core
(:use tupelo.test)
(:require
[tupelo.core :as t]))
(defn get-last
[items]
(when (empty? items)
(throw (IllegalArgumentException. "get-last: items must not be empty")))
(let [others (rest items)]
(if (empty? others)
(first items)
(get-last others))))
(dotest
(throws? (get-last []))
(is= 1 (get-last [1]))
(is= 2 (get-last [1 2]))
(is= 3 (get-last [1 2 3])))
Some people will insist that the above example is not "pure" enough, but I think explicit clarity beats out implicit behavior every time.
Update #2
When in doubt, ask the code what it is doing:
(defn my-last
[[x & xs]]
(t/spyx {:x x :xs xs})
(if xs
(t/spyx (my-last xs))
(t/spyx x)))
(dotest
(t/spyx (my-last [1 2 3])))
results with:
{:x x, :xs xs} => {:x 1, :xs (2 3)}
{:x x, :xs xs} => {:x 2, :xs (3)}
{:x x, :xs xs} => {:x 3, :xs nil}
x => 3
(my-last xs) => 3
(my-last xs) => 3
(my-last [1 2 3]) => 3
And there you have your answer.
TL;DR answer:
The first version was creating an infinite loop because that if statement will never be false since (rest [x]) and (rest []) return a truthy value
Pro Tip: Here are some fun ways to break on an empty sequence:
empty?
seq
(zero? (count coll))
The most idiomatic way is using seq with destructuring:
(fn my-last [[x & xs]]
(if (seq xs)
(my-last xs)
x))
but you could have also wrapped your original solution in seq and it would have worked:
(fn my-last [lst]
(if (seq (rest lst))
(my-last (rest lst))
(first lst)))
(seq (rest lst)) will return nil which is a falsey value when lst only has one element which is what you were checking for.
A side note, another way you could have solved this is to
! get the first element of the reversed collection since for problem 19 only last is banned
! (comp reverse first)

4clojure: set-intersection, recursive lambda

I am attempting to write a recursive lambda function (accepting two arguments) that finds the intersection between two (potentially) unsorted sets. Here is the code, which I believe most will find straight forward:
(fn intersection [a b]
(fn inner [x y out]
(if (empty? x) out
(if (nil? (some ((set (first x)) y )))
(inner (rest x) y out))))
(inner (rest x) y (cons (first x) out))
(inner a b '[])
)
I hope to use this lambda function intersection in place of the underscore _ that follows:
(= (__ #{0 1 2 3} #{2 3 4 5}) #{2 3})
However, this code fails to compile, insisting that Java is Unable to resolve symbol: inner in this context...
Any suggestions?
source: http://www.4clojure.com/problem/81
You could try :
#(set (filter %1 %2))
Since sets are functions (see another useful example there). The syntax with %1 and %2 is the same as writing :
(fn [s1 s2] (set (filter s1 s2)))
Or even more succinctly :
(comp set filter)
Regarding the inner error, you simply misplaced the parens (but I don't really see the logic otherwise) :
(fn intersection [a b]
(fn inner [x y out]
(if (empty? x) out
(if (nil? (some ((set (first x)) y )))
(inner (rest x) y out)))
(inner (rest x) y (cons (first x) out))
(inner a b '[])))
If you insist on building the set manually (which I did not so long ago), you could end up with something like that :
(fn [s1 s2]
(reduce #(if (contains? s2 %2) (conj %1 %2) %1) #{} s1))
But really the first solution is the most elegant.

Determining the cause of StackOverflow in code using lazy-seq

I have the following snippet:
(defn explode [e]
(seq [e e e e]))
(defn f [coll]
(when-first [e coll]
(cons e
(lazy-seq (f (lazy-cat (next coll)
(explode e)))))))
When I try to access an element, I get a StackOverflow error:
user=> (nth (f (seq [1 2 3])) 1000)
3
user=> (nth (f (seq [1 2 3])) 10000)
StackOverflowError clojure.core/concat/fn--3923 (core.clj:678)
How can I structure this code in a way that doesn't blow the stack?
You'll have to keep track of the remaining work explicitly, perhaps like so:
(defn f [coll]
(letfn [(go [xs q]
(lazy-seq
(cond
(seq xs)
(cons (first xs)
(go (next xs) (conj q (explode (first xs)))))
(seq q)
(go (peek q) (pop q)))))]
(go coll clojure.lang.PersistentQueue/EMPTY)))
From the REPL:
(nth (f [1 2 3]) 1000)
;= 3
(nth (f [1 2 3]) 10000)
;= 2
;; f-orig is f as found in the question text
(= (take 1000 (f-orig [1 2 3])) (take 1000 (f [1 2 3])))
;= true

Difference between iterate and repeatedly applying a function

I'm studying the Clojure Koans:
https://github.com/functional-koans/clojure-koans/blob/master/src/koans/10_lazy_sequences.clj
I am stuck on this one:
"Iteration can be used for repetition"
(= (repeat 100 :foo)
(take 100 (iterate ___ :foo)))
I don't know the exact builtin function to fill in the _ blanks with, so I tried writing my own. I wrote it as a separate function as a test.
I intend this one to be: if x is a seq, then just repeat its first element. Otherwise, make it a seq.
(def f (fn [x] (if (seq? x) (cons (first x) x) (cons x '()))))
When I run it explicitly, it looks fine:
user=> (f :abc)
(:abc)
user=> (f (f :abc))
(:abc :abc)
user=> (f (f (f :abc)))
(:abc :abc :abc)
But using iterate adds an extra parenthesis:
user=> (take 1 (iterate f :abc))(:abc)
user=> (take 2 (iterate f :abc))
(:abc (:abc))
user=> (take 3 (iterate f :abc))
(:abc (:abc) (:abc :abc))
What causes this?
(fn [x] x)
solves this particular koan
Re-read the documentation for iterate:
Returns a lazy sequence of x, (f x), (f (f x)) etc.
Use nth instead of take if you want the results of a particular iteration:
user=> (nth (iterate f :abc) 0)
:abc
user=> (nth (iterate f :abc) 1)
(:abc)
user=> (nth (iterate f :abc) 2)
(:abc :abc)
user=> (nth (iterate f :abc) 3)
(:abc :abc :abc)
I've solved it with #(keyword %)
I've tried with #( %) but it doesn't work. Anyone knows why?

recursion in clojure

I am trying to make this sample program work
(defn foo
([x] (foo x []))
([x current]
(when (> x 0)
(recur (dec x) (conj current x)))))
When I call this function (foo 5), I should get [1 2 3 4 5], however it only returns nil. What am I doing wrong?
Thanks,
Murtaza
Your recursion doesn't have a return expression i.e when then when is false the recursion terminates and it returns nil. You can fix this using if as:
(defn foo
([x] (foo x []))
([x current]
(if (> x 0)
(recur (dec x) (conj current x))
current)))
This will return [5 4 3 2 1] for (foo 5) as you are using vector as return value and conj on vector appends the item at the end of the vector. You can either reverse the vector or use list i.e in place of (foo x []) use (foo x '())
The code below works. I was not returning the final value.
(defn foo
([x] (foo x []))
([x current]
(if (> x 0)
(recur (dec x) (conj current x))
current)))
I have corrected your original program to use (if (= x 0) instead of (when (> x 0), and this returns [1 2 3 4 5].
(defn foo
([x] (foo x []))
([x current]
(if (= x 0)
(apply vector (sort < current))
(recur (dec x) (conj current x)))))