I'm new to Scheme and am trying to have an if-statement perform more than one action if its condition is true. I tried something like:
(if (char=? (string-ref str loc) #\a)
((+ count 1) (+ reference 1))
~else action, etc.~
And it complains about my action, saying
application: not a procedure
If I remove the parentheses, so that the action for a true condition is:
(+ count 1) (+ reference 1)
It complains
if: bad syntax
and fails to run at all. What am I missing?
There are two problems with the code. The first, an if form can't have more than one expression in the consequent and in the alternative. Two possible solutions for that - you can either use begin (not just a couple of parenthesis, that's for procedure application) to surround multiple expression:
(if (char=? (string-ref str loc) #\a)
; needs an explicit `begin` for more than one expression
(begin
(+ count 1)
(+ reference 1))
; needs an explicit `begin` for more than one expression
(begin
~else action, etc~))
... or use a cond, which is a better alternative because it already includes an implicit begin:
(cond ((char=? (string-ref str loc) #\a)
; already includes an implicit `begin`
(+ count 1)
(+ reference 1))
(else
; already includes an implicit `begin`
~else action, etc~))
The second problem is more subtle and serious, both of the expressions in the consequent part are probably not doing what you expect. This one: (+ count 1) is doing nothing at all, the incremented value is lost because you didn't use it after incrementing it. Same thing with the other one: (+ reference 1), but at least here the value is being returned as the result of the conditional expression. You should either pass both incremented values along to a procedure (probably as part of a recursion):
(cond ((char=? (string-ref str loc) #\a)
; let's say the procedure is called `loop`
(loop (+ count 1) (+ reference 1)))
(else
~else action, etc~))
Or directly update in the variables the result of the increments, although this is not the idiomatic way to write a solution in Scheme (it looks like a solution in C, Java, etc.):
(cond ((char=? (string-ref str loc) #\a)
; here we are mutating in-place the value of the variables
(set! count (+ count 1))
(set! reference (+ reference 1)))
(else
~else action, etc~))
If you're trying to perform multiple actions with side-effects in one arm of the if, then you'll need to put them into a begin, like this:
(if (char=? (string-ref str loc) #\a)
(begin (set! count (+ count 1))
(set! reference (+ reference 1)))
~else action, etc.~
If, instead of causing changes in variables, you want to return two values at once, then you'll either need to combine the expressions into a single object, like this:
(if (char=? (string-ref str loc) #\a)
(cons (+ count 1) (+ reference 1)))
~else expression~
in which case to pull out the count and reference, you'll need to apply car and cdr to the result of the if—or you could actually return multiple values, like this:
(if (char=? (string-ref str loc) #\a)
(values (+ count 1) (+ reference 1)))
~else expression~
in which case to pull out the count and reference, you'll need to bind the multiple values to variables somehow in the code that calls the if. One way to do that is with let-values, possibly something like this:
(define count&ref
(λ (str ch)
(let loop ([loc 0] [count 0] [reference 0])
; whatever other stuff you're doing
(if (char=? (string-ref str loc) ch)
(values (+ count 1) (+ reference 1)))
~else expression~ )))
(let-values ([(new-count new-ref) (count&ref "some stuff" #\u)])
;in here, new-count and new-ref are bound to whatever count&ref returned
)
On the other hand, if count and reference are variables that you're just keeping track of within a loop, the simplest way might be to call the next iteration of the loop inside the if, like this:
(let loop ([loc 0] [count 0] [reference 0])
; whatever other stuff you're doing
(if (char=? (string-ref str loc) #\a)
(loop (+ loc 1) (+ count 1) (+ reference 1))
~else expression~ ))
You can use begin to group a set of expressions to be executed one by one.
(if (char=? (string-ref str loc) #\a)
(begin (+ count 1) (+ reference 1))
~else action, etc.~
begin only returns the value of the last expression, that is (+ reference 1), so the value of (+ count 1) is not used.
Related
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))
To preface this, I'm very new to Clojure. I was wondering why I'm getting a ClassCastExpection on this piece of code. I've looked at it and syntactically and logically it looks correct?
Clojure Code:
; (load-file "cje842asg1.clj")
(def lstnum '(76 85 71))
; 2a
(defn sum [list] (
(if (empty? list)
0
(+ (first list (sum (rest list))))
)
)
)
; if empty return zero, else add the first num in list and pass in the
; rest.
(sum lstnum)
Any help is appreciated.
The code has 2 separate errors.
The first is calling (first list (sum (rest list))) which is calling first with 2 arguments when you meant to make the second part the second argument to +.
The other one leading to the actual exception is the extra () around the function body. Note the ((if ...)) which means you are trying to call whatever the if returns as a function. In this case it is returning a number, leading to the class java.lang.Long cannot be cast to class clojure.lang.IFn error.
The corrected version would be
(defn sum [list]
(if (empty? list)
0
(+ (first list)
(sum (rest list)))))
Moving the arguments to + into separate lines makes it easier to read in this case (IMHO).
As I've come to know it, the form of an if is (if [condition] [true] [false]). Similarly, cond is (cond [condition] [true] ... [condition] [true] [false]). Each true and false segment seems to only accept one action. If I want to represent the following logic:
if (i > 0)
{
a += 5;
b += 10;
}
I think I have to do:
(if (> i 0) (def a (+ a 5)))
(if (> i 0) (def b (+ b 10)))
Just so the second action isn't confused as a false result. Is this how it needs to be, or is there a way to create a larger body for an if?
p.s. I also suspect redefining a and b each time isn't the best way to increment, but also haven't seen a different way of doing that. I've had to also redefine lists when using conj.
The most direct transaction, using atoms instead of vars (def), would be
;; assuming something like (def a (atom 0)) (def b (atom 0))
(if (> i 0)
(do
(swap! a + 5)
(swap! b + 10)))
or
(when (> i 0)
(swap! a + 5)
(swap! b + 10))
You are looking through the wrong end of the telescope. Bear in mind that
Clojure has no local variables.
Clojure has no actions (usually called statements), only expressions returning a value.
There is no Clojure equivalent of the statement a += 5;.
However, expressions can have side effects: print and the like accomplish nothing else. The do form allows you to accomplish a series of side effects before returning a final value. For example,
(do (print a) (print b) (+ a b))
prints a,
prints b,
returns their sum.
That's why, as you write of the if form ...
Each true and false segment seems to only accept one action.
What Clojure does have is
local name bindings, with the let form and
a derived version of let called loop that implements a primitive
form of recursion that can replace simple uses of loops in
languages like C or Java.
Between them, let and its offspring loop allow you to write most simple control structures. to determine if this applies to your program fragment ...
if (i > 0)
{
a += 5;
b += 10;
}
... we'd have to see the context.
However, here's a greatest common divisor function in C (untested)
long gcd (long i, long j)
{
long m = i, n = j;
while (n != 0)
{
long t = n;
n = m % n;
m = t;
}
}
and in Clojure
(defn gcd [i j]
(loop [m i, n j]
(if (zero? n)
m
(recur n (mod m n)))))
Both of these can be abbreviated.
The other answer covered the explicit question about having more than one expression in the if branch (using do or by using when if there is no else branch as when wraps its nested expressions implicit do).
However, there is another issue in the question with using state which is usually local to the function. I don't think an atom stored in a global var is the best way to handle that, and as Clojure programs tend to minimise global state it's usually better to keep the state local.
We use let to define the local state and narrow its scope (NB it also supports destructuring):
(let [i 0
a 5
b 10]
(println i)
(println a)
(println b))
let assigns a value to a local variable and it cannot be redefined. If we need to update local state we can use recursion by calling recur directly on the function or by using loop and recur.
For example:
(defn plus [a b]
(if (> b 0)
(do
(println "Recurring...")
(recur (inc a) (dec b)))
(do
(println "Returning result")
a)))
Or:
(defn plus [a b]
(loop [a a
b b]
(if (> b 0)
(do
(println "Recurring...")
(recur (inc a) (dec b)))
(do
(println "Returning result")
a))))
(define [DML vara]
(cond
((atom? (car vara))
(cond
((eqan? (car vara) 'N)
(display (cdr vara)))
(else (negate vara)))
)))
I'm currently trying to save the content of a return right now for simplicity I was testing the negate function it "returns" a list and I wanted to save the result of that function to do testing. How do I actually save the list return from negate.
Kind of like (x = (negate vara)) where x is the list. I look up let on google and in stack over flow but I can't find a very simple basic assignment.
Excuse my poor syntax on scheme I'm just starting..and going from imperative language to function isn't so smooth..
edit:
I wanted to print out the result expression of (negate vara) but since scheme only prints out the last "recursive call" (pardon my bad wording). I wanted it to use the resulting list from (negate vara) but still print out that list like
say if I had
(else (test (negate vara)))
...
(define (test vara)
(display "test")
)
I wanted it to display
'(O a b)) ;list
here
As you already know, a let expression will do the trick:
(let ((x 10)
(y 20))
(+ x y))
=> 30
The above expression binds values to two variables, x and y. These bindings will exist inside the body of the let. Implicitly, all the expressions in the let form are packed inside a begin, and the end result of the whole expression is the final expression. Notice that one binding cannot refer to the others in the definition part; if one variable needs to refer to previous definitions, then use a let*:
(let* ((x 10)
(y (* x 2)))
(+ x y))
=> 30
Finally, if you need to create a recursive definition use letrec:
(letrec ((fact (lambda (x)
(if (zero? x) 1 (* x (fact (sub1 x)))))))
(fact 10))
=> 3628800
You could make a procedure like you proposed:
(define (test var)
(display var)
var)
(test (negate (test vara)))) ; prints our argument and return
Or you could use DrRacket and use the debugger. You'll miss it after using it once!
*Simple question : Why does this function throw an exception when evaluated ? *
In the case where there is a duplicate in the string , there is a Class cast exception thrown upon finding the duplicate.
In the case where the string has no duplicates, a NullPointerException is thrown.
*The Code *
(defn first-duplicate-char [str-in]
(loop [list-Rem (seq str-in) set-Seen (set [])]
(print (type list-Rem) " " list-Rem (next list-Rem) "\n")
(if (= 0 (count str-in))
nil
(if (some #(= (first list-Rem) %) set-Seen)
(first list-Rem)
(recur
(seq (next list-Rem))
(conj set-Seen (first list-Rem)))))))
Your problem is that (= 0 (count str-in)) never changes, so you eventually try to call first on nil. [EDIT: I'm wrong, your code actually works as is -- that if statement is just a no-op. I hope you enjoy the rest of this answer anyway.]
Instead, you should be calling next (not rest) on list-Rem in the recur and using list-Rem directly in the if test, using the property of next that returns nil for an empty seq. Here's how I would rewrite your code:
(defn first-duplicate [in]
(loop [seen #{}
remain (seq in)]
(when-let [[head & tail] remain]
(if (contains? seen head)
head
(recur (conj seen head) tail)))))
Changes:
lowercasing names
no need to call seq on the output of next or rest
with sets, contains? (check for existence of key) is faster than some (run a predicate on elements until something yields a truthy value)
set literal
using when to return nil on test failure
using when-let to destructure and bind first char and rest
Stylistic changes:
names changed to be less specific (not restricted to strings, for instance)
change order of loop locals so that recur looks more like structural recursion
put loop locals on separate lines