For example, how can I do three different things in the same 'else' branch in Racket?
Like
(if (equal? temp2 #f)
#f
temp2
(vector-set! cache counter temp2)
(set! counter (+ counter 1)))
)
Put the expressions that need to be executed sequentially inside a (begin ...) block, or use a cond expression, which implicitly uses a begin block. Like this:
(if <condition>
(begin ; consequent
exp1
exp2)
(begin ; alternative
exp3
exp4))
Or even simpler:
(cond (<condition>
exp1 ; consequent
exp2)
(else
exp3 ; alternative
exp4))
Related
I am going through the tutorial at Lisp Tutor Jr, on my own.
After completing an assignment on recursion, I started thinking about expanding the numeric range to negative numbers.
If I bind as in the following code, it gets adjusted together with x.
1) Do I understand correctly that using defconstant inside the function is wrong?
2) How would I bind a minimal variable based on x, in this case attempted via (- x).
(defun list-odd-range(x)
(let ((neg (- x)))
(cond
((< x neg) nil)
((oddp x)(cons x (list-odd (1- x))))
(t (list-odd (1- x))))))
The function as-is returns
(list-odd 5)=>(5 3 1)
I would like to bind neg once, as (- x)
and have the function return a range from positive to negative x:
(list-odd 5)=>(5 3 1 -1 -3 -5)
Binding with an integer, such as the following bit, works:
(let ((neg -5))
What is the correct way to have it defined in relation to x, such as (- x) ?
1) Defconstant doesn't really make sense in a function. It defines a global constant, which is constant. If you ever call the function again, you either provide the same (eql) value and have no effect, or a different value, which is illegal.
2) As you observed, the inner call doesn't know anything about the outer environment except what is passed as an argument. You can either keep it at that and add the remaining part after the return of the inner call (I elide checking the inputs in the following, you'd need to make sure that x is always a nonnegative integer):
(defun odd-range (x)
(cond ((zerop x) ())
((evenp x) (odd-range (1- x)))
(t (cons x
(append (odd-range (1- x))
(list (- x)))))))
Or you can pass the end number along as an additional argument:
(defun odd-range (start end)
(cond ((< start end) ())
((evenp start) (odd-range (1- start) end))
(t (cons start
(odd-range (1- start) end)))))
This would have the benefit of giving the caller free choice of the range as long as end is smaller than start.
You can also pass along the constructed list so far (often called an accumulator, abbreviated acc):
(defun odd-range (start end acc)
(cond ((< start end) (reverse acc))
((evenp start) (odd-range (1- start) end acc))
(t (odd-range (1- start) end (cons start acc)))))
This conses to the front of the list while accumulating and only reverses the result at the end. This avoids walking the accumulated list at every step and is a big improvement on running time. It also moves the recursive call into tail position so that the compiler may produce code that is equivalent to a simple loop, avoiding stack limits. This compiler technique is called tail call elimination or tail call optimization (TCO).
Since Common Lisp compilers are not required to do TCO, it is good style to write loops actually as loops. Examples:
(defun odd-range (start)
(do ((x start (1- x))
(end (- start))
(acc ()
(if (oddp x)
(cons x acc)
acc)))
((<= x end) (reverse acc))))
(defun odd-range (x)
(let* ((start (if (oddp x) x (1- x)))
(end (- start)))
(loop :for i :from start :downto end :by 2
:collect i)))
I'm quite new to functional programming, especially Scheme as used below. I'm trying to make the following function that is recursive, tail recursive.
Basically, what the function does, is scores the alignment of two strings. When given two strings as input, it compares each "column" of characters and accumulates a score for that alignment, based on a scoring scheme that is implemented in a function called scorer that is called by the function in the code below.
I sort of have an idea of using a helper function to accumulate the score, but I'm not too sure how to do that, hence how would I go about making the function below tail-recursive?
(define (alignment-score string_one string_two)
(if (and (not (= (string-length string_one) 0))
(not (=(string-length string_two) 0)))
(+ (scorer (string-ref string_one 0)
(string-ref string_two 0))
(alignment-score-not-tail
(substring string_one 1 (string-length string_one))
(substring string_two 1 (string-length string_two))
)
)
0)
)
Just wanted to make an variant of Chris' answer that uses lists of chars:
(define (alignment-score s1 s2)
(let loop ((score 0)
(l1 (string->list s1))
(l2 (string->list s2)))
(if (or (null? l1) (null? l2))
score
(loop (+ score (scorer (car l1)
(car l2)))
(cdr l1)
(cdr l2)))))
No use stopping there. Since this now have become list iteration we can use higher order procedure. Typically we want a fold-left or foldl and SRFI-1 fold is an implementation of that that doesn't require the lists to be of the same length:
; (import (scheme) (only (srfi :1) fold)) ; r7rs
; (import (rnrs) (only (srfi :1) fold)) ; r6rs
; (require srfi/1) ; racket
(define (alignment-score s1 s2)
(fold (lambda (a b acc)
(+ acc (scorer a b)))
0
(string->list s1)
(string->list s2)))
If you accumulating and the order doesn't matter always choose a left fold since it's always tail recursive in Scheme.
Here's how it would look like with accumulator:
(define (alignment-score s1 s2)
(define min-length (min (string-length s1) (string-length s2)))
(let loop ((score 0)
(index 0))
(if (= index min-length)
score
(loop (+ score (scorer (string-ref s1 index)
(string-ref s2 index)))
(+ index 1)))))
In this case, score is the accumulator, which starts as 0. We also have an index (also starting as 0) that keeps track of which position in the string to grab. The base case, when we reach the end of either string, is to return the accumulated score so far.
I trying to write a function which gets an integer number , represented by string , and check if all his chars are digits and return #t \ #f accordingly . Thats the code -
(define (splitString str) (list->vector (string->list str)))
(define myVector 0)
(define flag #t)
(define (checkIfStringLegal str) (
(set! myVector (splitString str))
(do ( (i 0 (+ i 1)) ) ; init
((= i (vector-length myVector)) flag) ; stop condition
(cond ((>= 48 (char->integer (vector-ref myVector i)) ) (set! flag #f))
((<= 57 (char->integer (vector-ref myVector i)) )(set! flag #f))
)
)
)
)
Few explanations -
(list->vector (string->list str)) - convert string the char list .
(vector-ref myVector i) - char from the myVector at place i .
Its run OK , but when I try to use this func , like (checkIfStringLegal "444") I get -
application: not a procedure;
expected a procedure that can be applied to arguments
given: #<void>
arguments...:
#t
Try this:
(define (checkIfStringLegal str)
(andmap char-numeric?
(string->list str)))
This is how the procedure works:
It transforms the string into a list of characters, using string->list
It validates each character in the list to see if it's a number, applying the predicate char-numeric? to each one
If all the validations returned #t, andmap will return #t. If a single validation failed, andmap will return #f immediately
That's a functional-programming solution (and after all, this question is tagged as such), notice that your intended approach looks more like a solution in a C-like programming language - using vectors, explicit looping constructs (do), mutation operations (set!), global mutable definitions ... that's fine and it might eventually work after some tweaking, but it's not the idiomatic way to do things in Scheme, and it's not even remotely a functional-programming solution.
EDIT:
Oh heck, I give up. If you want to write the solution your way, this will work - you had a parenthesis problem, and please take good notice of the proper way to indent and close parenthesis in Scheme, it will make your code more readable for you and for others:
(define (splitString str) (list->vector (string->list str)))
(define myVector 0)
(define flag #t)
(define (checkIfStringLegal str)
(set! myVector (splitString str))
(do ((i 0 (+ i 1)))
((= i (vector-length myVector)) flag)
(cond ((>= 48 (char->integer (vector-ref myVector i)))
(set! flag #f))
((<= 57 (char->integer (vector-ref myVector i)))
(set! flag #f)))))
Even so, the code could be further improved, I'll leave that as an exercise for the reader:
Both conditions can be collapsed into a single condition, using an or
The exit condition should be: end the loop when the end of the vector is reached or the flag is false
(define l '(* - + 4))
(define (operator? x)
(or (equal? '+ x) (equal? '- x) (equal? '* x) (equal? '/ x)))
(define (tokes list)
(if (null? list)(write "empty")
(if (operator? (car list))
((write "operator")
(tokes (cdr list)))
(write "other"))))
The code works just fine til (tokes (cdr list))) reaches the end of file. Can someone give me a tip in how I can prevent that. I'm new at Scheme so I'm forgive me if the question is absurd.
You must make sure of advancing the recursion on each case (except the base case, when the list is null). In your code you're not making a recursive call for the (write "other") case. Also, you should use cond when there are several conditions to test, Let me explain with an example - instead of this:
(if condition1
exp1
(if condition2
exp2
(if condition3
exp3
exp4)))
Better write this, is much more readable and has the added benefit that you can write more than one expression after each condition without the need to use a begin form:
(cond (condition1 exp1) ; you can write additional expressions after exp1
(condition2 exp2) ; you can write additional expressions after exp2
(condition3 exp3) ; you can write additional expressions after exp3
(else exp4)) ; you can write additional expressions after exp4
... Which leads me to the next point, be aware that you can write only one expression for each branch of an if, if more than one expression is needed for a given condition in an if form then you must surround them with a begin, for example:
(if condition
; if the condition is true
(begin ; if more than one expression is needed
exp1 ; surround them with a begin
exp2)
; if the condition is false
(begin ; if more than one expression is needed
exp3 ; surround them with a begin
exp4))
Going back to your question - here's the general idea, fill-in the blanks:
(define (tokes list)
(cond ((null? list)
(write "empty"))
((operator? (car list))
(write "operator")
<???>) ; advance on the recursion
(else
(write "other")
<???>))) ; advance on the recursion
I need a recursive LISP function that enumerates the number of elements in any list of numbers > 3. I'm not allowed to use lets, loops or whiles and can only use basic CAR, CDR, SETQ, COND, CONS, APPEND, PROGN, LIST...
This is my attempt at the function:
(defun foo (lst)
(COND ((null lst) lst)
(T (IF (> (CAR lst) 3)
(1+ (foo (CDR lst)))
(foo (CDR lst)) ) ) ) )
The function call:
(foo '(0 1 2 3 4 5 6))
Your code is pretty close to correct, just a small mistake in the base case:
For the empty list you return the empty list. So if you have the list (6), you add 6 to foo of the empty list, which is the empty list. That does not work because you can't add a number to a list.
You can easily fix it by making foo return 0 instead of lst when lst is empty.
As a style note: Mixing cond and if like this, seems a bit redundant. I would write it like this, using only cond instead:
(defun foo (lst)
(cond
((null lst)
0)
((> (car lst) 3)
(1+ (foo (cdr lst))))
(T
(foo (cdr lst)))))
Some stylistic points:
There's no need to put some Lisp built-ins in uppercase. It's not 1958 anymore!
But if you are going to put built-ins in uppercase, why not DEFUN and NULL?
You have an if inside the last branch of your cond. This is redundant. Since the purpose of cond is testing conditions, why not use it?
There's no need to space out your closing parentheses like that. No-one counts parentheses these days, we have parenthesis-matching editors.
Lisp has separate namespaces for functions and values, so you don't have to call your argument lst to avoid conflicting with the built-in function list.
If you were programming this for real, of course you'd use count-if:
(count-if #'(lambda (x) (> x 3)) '(0 1 2 3 4 5 6))
==> 3
One save you can have on duplication of the recursive call:
(defun foo (l)
(if (null l) 0 ; if list is empty, return 0
(+ (if (> (car l) 3) 1 0) ; else +1 if condition is satisfactory
(foo (cdr l))))) ; plus the result from the rest