How can I add arity to this function? - clojure

I want this function
(defn ret-lowest-str-len
"Computes the lengths of two strings. Returns default length -- len --
if len is <= the length of str-1 and len is <= length of str-2.
Else, returns smaller of length of str-1 and str-2."
[str-1 str-2 len]
(let [l1 (count str-1)
l2 (count str-2)]
(if (and (<= len l1) (<= len l2))
len
(if (< l1 l2)
l1
l2))))
to be able to have two argument signatures. The example shows str-1 str-2 and len (a fixed length). This was done, so that if a string was less than the fixed default of say 15, a length value would be returned that would not cause an overrun exception.
I'd like to be able to pass just str-1 and len without str-2, and I'm not quite sure how to do it.
I'm aware the code will have to change if l2 is not passed in. I'm wondering how to set up the arity. Any examples would be appreciated.
Thanks.

defn has two syntaxes
(defn foo [] (expression) (expression))
and
(defn foo
([] (exp1) (exp2)) ; arity 0
([x] (exp1) (exp2)) ;arity 1
([x y] (exp1) (exp2)) ; arity 2
a common pattern is to have the lesser arity version fill in defaults and call into the higher arity case:
(defn ret-lowest-str-len
([str-1 len] (ret-lowest-str-len str-1 "" len))
([str-1 str-2 len]
(let [l1 (count str-1)
l2 (count str-2)]
(if (and (<= len l1) (<= len l2))
len
(if (< l1 l2)
l1
l2)))))
on a side note you could write a verry similar function using a variable number of arguments:
user> (defn ret-lowest-str-len [& args] (reduce min (map count args)))
#'user/ret-lowest-str-len
user> (ret-lowest-str-len "a" "aaaa" "aaaaaaaaa")
1

I would go further and make it work for any number of strings, using the & syntax for optional list of arguments, using something along the lines of:
(defn lowest-str-len [default-len & strs]
(let [lens (map count strs)]
(apply min default-len lens)))

Related

Find the longest integer in a vector using while loops

Working on this program that's supposed to take a vector of integers as input and return the one with the longest integer. Example (vector 20 738 5942 125) and would return 4 as its the longest one. I'm pretty sure I have most of this done the only issue I have is in the conditional as I have to call an outside function (count-integers), this is what I have so far:
(require while)
(define (empty-VINT? low high) (> low high))
(define (count-integers n)
(cond [(< n 10) 1]
(else(+ 1 (count-integers [/ n 10])))))
(define (count-digits V)
(local [
(define x (void))
(define accum (void))
(define largest 0)]
(begin
(set! x (vector-length V))
(set! accum 0)
(while (< accum (vector-length V))
(cond [(empty-VINT? x accum) accum]
[(> (count-integers (vector-ref V accum) largest)
(add1 x) accum(vector-ref V accum))]
[else add1 accum])))))
Right now when its run, I get this message: cond: expected a clause with a question and an answer, but found a clause with only one part. Any suggestions would be great, thanks
First of all, it's not clear what do you want to return. 4 isn't the longest integer (that's 5942), 4 is a maximal digit count among integers in given vector.
Secondly, your code isn't idiomatic and without your comment, it's very hard to say what's going on. Programming in functional languages requies functional way of thinking. Forget about while, set!, void, local and nested define and instead spend some time learning about apply, map, filter and foldl.
I would solve this problem like this:
(define (digits number)
(string-length (number->string number)))
(define (max-digit-count vec)
(apply max (map digits (vector->list vec))))
(max-digit-count (vector 20 738 5942 125))
=> 4
From comments:
Design and implement a function to find the number of digits in the longest integer in a (vectorof integer) ...
use ... while loops
So a plan (design) might be:
count-digits: integer -> natural
max-digit-count: (vectorof integer) -> natural
..something while something max count-digits something ???
Implementing count-digits seems straightforward (but
integers can be negative, and in Racket (integer? 123.000) is true).
#lang racket
(define (count-digits int) ;; Integer -> Natural
;; produce count of digits in int
(string-length (number->string (abs (exact-truncate int)))))
As #Gwang-Jin Kim mentions, while could be defined:
(define-syntax-rule (while condition body ...)
;; From: https://stackoverflow.com/questions/10968212/while-loop-macro-in-drracket
(let loop ()
(when condition
body ...
(loop))))
and then one could use it:
(define (max-digit-count vec) ;; VectorOfInteger -> Natural
;; produce maximum of digit counts of vec elements
(define vx 0)
(define acc 0)
(while (< vx (vector-length vec))
(set! acc (max accum (count-digits (vector-ref vec vx))))
(set! vx (add1 vx)))
acc)
(max-digit-count (vector 20 -738.00 5942 125)) ;=> 4
One of the problems with while is that it can't produce a value (where would it come
from if the condition is false on entry?)
If one "enhanced" while a bit:
(define-syntax-rule (while< x-id limit a-id a-init update)
;; "while loop" incrementing x-id from 0 to limit-1, updating a-id
(let loop ([x-id 0] [a-id a-init])
(if (< x-id limit)
(loop (add1 x-id) update)
a-id)))
max-digit-count could be neater:
(define (max-digit-count vec) ;; VectorOfInteger -> Natural
;; produce maximum of digit counts of vec elements
(while< vx (vector-length vec)
acc 0 (max acc (count-digits (vector-ref vec vx)))))
#MartinPuda's answer is quite good.
I would have defined:
(define (digits n (acc 0))
(if (< n 1)
acc
(digits (/ n 10) (+ acc 1))))
(define (max-digits lst)
(digits (car (sort lst >))))
To apply it:
(max-digits (vector->list (vector 20 738 5942 125)))
Why you should not use while
Using while would force you to mutate variable values. It is much more "natural" for lisp languages to follow the functional style (recursive functions instead of while loops or other loops) rather than the imperative style with mutation of variables.
That is why while is not in the lisp languages.
But if you want to use it:
(define-syntax-rule (while condition body ...)
;; From: https://stackoverflow.com/questions/10968212/while-loop-macro-in-drracket
(let loop ()
(when condition
body ...
(loop))))
(define (digits n (acc 0))
(cond ((< n 1) acc)
(else (digits (/ n 10) (+ acc 1)))))
(define (max-digits lst)
(let ((max-digit 0))
(while (not (null? lst))
(let ((digit (digits (car lst))))
(when (< max-digit digit)
(set! max-digit digit))
(set! lst (cdr lst))))
max-digit))
Then you can try:
> (max-digits (vector->list v))
4
> (max-digits '(1111 123456 2345 34))
6
Prefer let over define
Why? Because if you use let, you can control the scope of the to-be-mutated variable very precisely. You can define in your definition, from where on your variable canNOT have any effect on your code (since its scope ended at some point). While with define you don't have this fine-grained control. (Or this control is implicit not explicite like with let). You could delete/unbind the variable explicitely but that is rarely done in real life.
Therefore, in Lisp, for variable declarations use whenever possible let, especially whenever you deal with mutated variables.
All imperative = declarations should be in Lisp languages let expressions!
You can use function arguments instead of let-definitions, because they are anyway implemented using lets
Just you save syntactically some lines - and the fewer lines you occupy the cleaner the code.
#lang racket
(define (digits n)
(string-length (number->string n)))
(define (max-digit a b)
(if (< (digits a) (digits b)) b a))
(define (max-digits lst (res ""))
(while (not (null? lst))
(set! res (max-digit res (car lst)))
(set! lst (cdr lst)))
(digits res))

How to pass function as parameters

I have a function that receives a vector and sum all the elements.
(def rec
(fn [numbers acc]
(if (empty? numbers)
acc
(recur (rest numbers) (+ acc (first numbers))))))
(prn (rec [1 2 3] 0))
But instead of calling the function "+" I want to pass the operation as parameter, it means, I want to pass a function as parameter and then call the function.
I tried:
(def rec
(fn [f numbers acc]
(if (empty? numbers)
acc
(recur (rest numbers) (f acc (first numbers))))))
(prn (rec + [4 2 1] 0))
But it does not work, I know there are better ways to sum numbers in a vector, but I'm starting with functional, so it is important to do this kind of exercise.
Thanks in advance.
You need to recur with the same arguments as the parameter vector, in this case:
(recur f (rest numbers) (f acc (first numbers))))))
(btw, it's standard to use defn for defining functions, (defn f[x] ... ) is more concise than (def f (fn [x] ...)))
More ideomatic Clojure would be using reduce here, I think
(defn rec [f numbers acc]
(reduce f acc numbers))
(rec + [1 2 3] 0)
# 6
Factoring
In your
(def rec
(fn [numbers acc]
(if (empty? numbers)
acc
(recur (rest numbers) (+ acc (first numbers))))))
... you can push the accumulator acc beneath the surface of rec:
(defn rec [numbers]
(loop [ns numbers, acc 0]
(if (empty? ns)
acc
(recur (rest ns) (+ acc (first ns))))))
For example,
(rec + [1 3])
; 4
If you want to pass the operation as a parameter, the convention is that calling it with no arguments gives its identity: the value which returns the other argument when it is applied to two.
Thus
(+) ; => 0
(*) ; => 1
So we can write your parameterized rec as
(defn rec [op numbers]
(loop [ns numbers, acc (op)]
(if (empty? ns)
acc
(recur (rest ns) (op acc (first ns))))))
This is almost how reduce works, though not quite as elegantly, IMO.

Correct use of `recur` in Clojure?

I'm trying to solve the Count a Sequence problem on 4Clojure, but I can't work out what's wrong with my use of recur:
fn [s] (
fn [t n] (
if (empty t)
n
(recur (rest t) (+ n 1))
) s 0
)
It gives the following exception:
java.lang.UnsupportedOperationException: Can only recur from tail position, compiling:(NO_SOURCE_PATH:0)
But to me it seems that the call to recur is in a tail position for the inner function. What am I missing?
Two problems:
Your parentheses are misplaced.
You are using empty where you want empty?.
Parentheses
The fn special form for defining a function takes the shape
(fn name? [params* ] exprs*) with the parentheses around it.
Another level of parentheses applies the function ((fn [n] (* n n))
3) => 9.
Using defn instead of fn for the moment, we get
(defn l [s]
((fn [t n] (if (empty? t) n (recur (rest t) (+ n 1))))
s 0))
Then, for example,
(l ())
; 0
and
(l [1 2 3])
; 3
#Thumbnail is right -- your code will work just fine if you fix the placement of your parentheses (most importantly, you need to add a ( before (fn [t n] ... and a corresponding ) after s 0, in order to actually return the result of calling that function (the one that takes t and n as arguments) on the values s and 0. Otherwise, you are returning the function itself.), and change empty to empty?.
If you wanted to simplify things a bit, you might consider using a loop/recur structure instead, like this:
(fn [s]
(loop [t s, n 0]
(if (empty? t)
n
(recur (rest t) (+ n 1)))))

Weird behaviour binding in loop recursion

I'm learning Clojure, and I'm trying to solve the Problem 31: Write a function which packs consecutive duplicates into sub-lists.
(= (__ [1 1 2 1 1 1 3 3]) '((1 1) (2) (1 1 1) (3 3)))
I know I can solve this using identity, and in a functional way, but I want to solve it using recursion, because I've not well established this idea in my brain.
My solution would be this:
(defn packing [lista]
(loop [[fst snd :as all] lista mem [] tmp '(fst)]
(print "all is " all "\n\n") ;; something is wrong; it always is an empty list
(if (seq? all)
(if (= fst snd)
(recur (rest all) mem (cons snd tmp))
(recur (rest all) (conj mem tmp) (list snd)))
(seq mem))))
My idea is a recursive loop always taking the first 2 items and comparing. If they are the same number, I include this inside a temporary list tmp; if they're different, I include my temporary list inside men. (This is my final list; a better name would be final_list.)
Because it compares the first 2 items, but at the same time it needs a recursive loop only bypassing the first item, I named the entire list all.
I don't know if the logic is good but inclusive if this was wrong I'm not sure why when I print.
(print "all is " all "\n\n") I receive an empty list
A few points:
'(fst) creates a list containing a symbol fst, not the value of fst, this is one of the reasons to prefer using vectors, e.g., [fst]
you should avoid assuming the input will not be empty
you can use conj for both lists and vectors
destructuring is nestable
(defn packing [coll]
(loop [[x & [y :as more] :as all] coll
result []
same '()]
(if all
(if (= x y)
(recur more result (conj same x))
(recur more (conj result (conj same x)) '()))
result)))
in your code all isn't empty..only happen than is an infinite loop and you always see a empty list...in the firsts lines you can see than it works like expected..
the mistake is in (seq? all) because a empty list is a seq too... try (seq? '()) and return true...then you do a empty loop
you need change this for (empty? all) your code would be
other mistake is '(fst) because it return the simbol fst and not the value...change it for (list fst)
(defn badpacking [lista]
(loop [[fst snd :as all] lista mem [] tmp (list fst)]
(if (empty? all)
(seq mem)
(if (= fst snd)
(recur (rest all) mem (cons snd tmp))
(recur (rest all) (conj mem tmp) (list snd))))))

Grouping a sequence of bools in clojure?

I would like to transform the following sequence:
(def boollist [true false false false true false true])
Into the following:
[[true] [false false false true] [false true]]
My code leads to a Stackoverflow:
(defn sep [boollst]
(loop [lst boollst
separated [[]]
[left right] (take 2 lst)]
(if (nil? left) separated)
(recur (next lst)
(if (false? left)
(conj (last separated) left)
(conj separated [left]))
(take 2 (next lst)))))
Is there an elegant way of transforming this?
There's probably a much more elegant way, but this is what I came up with:
(defn f
([xs] (f xs [] []))
([[x & xs :as all] acc a]
(if (seq all)
(if x
(recur xs [] (conj a (conj acc x)))
(recur xs (conj acc x) a))
a)))
It just traverses the sequence keeping track of the current vector of falses, and a big accumulator of everything so far.
A short, "clever" solution would be:
(defn sep [lst]
(let [x (partition-by identity lst)]
(filter last (map concat (cons [] x) x))))
The "stack overflow" issue is due to the philosophy of Clojure regarding recursion and is easily avoided if approached correctly. You should always implement these types of functions* in a lazy way: If you can't find a trick for solving the problem using library functions, as I did above, you should use "lazy-seq" for the general solution (like pmjordan did) as explained here: http://clojure.org/lazy
* Functions that eat up a list and return a list as the result. (If something other than a list is returned, the idiomatic solution is to use "recur" and an accumulator, as shown by dfan's example, which I would not consider idiomatic in this case.)
Here's a version that uses lazy evaluation and is maybe a little more readable:
(defn f [bools]
(when-not (empty? bools)
(let
[[l & r] bools
[lr rr] (split-with false? r)]
(lazy-seq (cons
(cons l lr)
(f rr))))))
It doesn't return vectors though, so if that's a requirement you need to manually pass the result of concat and of the function itself to vec, thus negating the advantage of using lazy evaluation.
The stack overflow error is because your recur is outside of the if. You evaluate the if form for side effects, then unconditionally recur. (feel free to edit for format, I'm not at a real keyboard).