Trying to understanding recursion and why an error is occurring - recursion

I am writing a program which takes in a list and outputs true if the elements in the list alternate signs. For example if the first number is positive, the second number must be negative and then the third number must be positive again and so on.
I've tried implementing a simple cond statement (shown in the code) but keep coming across an error in my check-expect. The error states: first: expects only 1 argument, but found 2.
(define (alternating? lst)
(cond [(empty? lst) true]
[(> (first lst) 0)
(cond [(< (first (rest lst) 0)) (alternating? (rest lst))])]
[(< (first lst) 0)
(cond [(> (first (rest lst) 0)) (alternating? (rest lst))])]
[else false]))
When looking at the code, it looks like first does in fact only take in one argument from the list, but the error says that this is not the case.

On lines 3 and 5, you are correctly calling first with one argument, namely lst:
(first lst)
On lines 4 and 6, you are calling first with two arguments, namely (rest lst) and 0:
(first (rest lst) 0)
I think what you want is this:
(< (first (rest lst)) 0)
; ↑ ↑
instead of this:
(< (first (rest lst) 0))
; ↑ ↑

Related

DrRacket - find the longest increasing subsequence

I want to create code for finding LIS. My code doesn't work very well. For example if the input is '(1 3 5 10 9 6 7), output should be '(1 3 5 6 7) but my program return '(1 3 5 10). What am I doing wrong? Have I code binary tree and then find the higher height? Or can I code this program in easiest way?
(define (return_sequence N lst)
(cond
[(empty? lst) '()]
[(< N (first lst)) (cons
(first lst)
(return_sequence (first lst) (rest lst))
)]
[else (return_sequence N (rest lst))]
)
)
(define (find_longest lst1 lst2)
(cond
[(empty? lst1) lst2]
[(empty? lst2) lst1]
[(< (length lst1) (length lst2)) lst2]
[else lst1]
)
)
(define (LIS lst)
(cond
[(empty? lst) '()]
[else (find_longest
(cons
(first lst)
(return_sequence (first lst) (rest lst)))
(LIS (rest lst))
)]
)
)
Before we begin, a question. Do you consider '(1 1) to be an increasing sequence? For now, I will assume you do not.
First, note that we can simplify find-longest as follows:
(define (find-longest lst1 lst2)
(if (<= (length lst1)
(length lst2))
lst1
lst2))
This is terribly inefficient, but we won't worry about that for now. It at least looks cleaner than your code.
I assume that you're trying to define (return_sequence N lst) to be the longest increasing subsequence of lst such that all elements of said subsequence are greater than N. I suggest you take a look at exactly what happens when you try (return_sequence 1 '(4 2 3)). We should expect the result to be '(2 3), but it is in fact '(4).
You need to think carefully about exactly how you want to handle the case where (< N (first lst)) and make sure you're not making a silly mistake (spoiler - you are making a silly mistake).
Edit: suppose that (< N (first lst)). The longest increasing subsequence of lst where all elements are greater than N either contains (first lst) or doesn't. To find the longest subsequence that doesn't, we compute (return_sequence N (rest lst)). To find the longest subsequence that does, we compute (cons (first lst) (return_sequence (first lst) (rest lst)). The relevant cond clause becomes
[(< N (first lst)) (find_longest
(cons (first lst)
(return_sequence (first lst) (rest lst)))
(return_sequence N (rest lst)))]
and this solves your problem.
On another note, it's extremely helpful to add in the value of minus-infinity, with the condition that this value is always less than any other value. In that case, we can just do
(define (LIS lst)
(return_sequence minus-infinity lst))
Doing this requires a little bit of cleverness, but it is possible.
In fact, one clever way to add minus_infinity is to pass into return_sequence not a number N, but the function (lambda (x) (< N x)). Then, instead of the line (< N (first list)), you would instead write (less_than_N (first list)). Then, you can (define (minus_infinity x) #t).
It's also possible to create a new symbol using gensym and have that be minus_infinity. You'd then want to do something rather cheeky like
(define minus_infinity (gensym))
(define (return_sequence N lst)
(let ((< (lambda (a b) (or (equal? a minus_infinity) (< a b)))))
cond ...)
(define (LIS lst)
(return_sequence minus_infinity lst))
with the cheeky bit being that we're not defining (<) recursively - the < that occurs in (lambda (a b) (or (equal? a minus_infinity) (< a b))) is the original <.
Finally, the algorithm you're trying is really slow. It's possible to solve this problem in O(n log n) where n = (length lst). Your solution will be an exponential time one, but improving it is highly nontrivial.

Writing an alternating series checker in racket

I am trying to make a program which determines if an inputted list alternates in sign. For example, my program would return true if given the list(s): [-1, 5, -10] or [5, -17, 25]. The program would return false if given the list(s): [-1, -5, 6] or [1, -2, -6].
I've tried making a simple cond statement which checks the sign of the first number in the list and then after checks the second number in the list to make sure the first number was positive and the second number was negative or the first number was negative and the second number was positive.
(define (alternating-signs-in-list? lst)
(cond
[(> (first lst) 0)
(cond [(< (first (rest lst)) 0) (alternating-signs-in-list? (rest lst))])]
[(< (first lst) 0)
(cond [(> (first (rest lst)) 0) (alternating-signs-in-list? (rest lst))])]
[else false]))
I expected the code presented to work but was met with an error stating:
first: expects a non-empty list; given: empty
This error occurred when I made the following check-expect:
(check-expect (alternating-signs-in-list? (cons 1 (cons -5 (cons 50 empty)))) true).
Why is the following error occurring and is there an easy fix I can make to get my code to start working. Thank you.
The trick is to compare pairs of elements at the same time (first and second of the list), until the list is exhausted. The error you're receiving is because you forgot to handle the empty-list case, and for this problem in particular, we also need to handle the case when the list has a single element left.
Before proceeding, it's useful to implement a same-sign? procedure, it's easy if we leverage the sgn procedure (that returns the sign of a number), and if we assume that 0 is positive:
(define (same-sign? n1 n2)
; they have the same sign if their `sgn` value is the same
(= (if (zero? n1) 1 (sgn n1))
(if (zero? n2) 1 (sgn n2))))
The main procedure goes like this:
(define (alternating-signs-in-list? lst)
(cond ((or (empty? lst) (empty? (rest lst))) #t) ; empty list / single element case
((same-sign? (first lst) (second lst)) #f) ; they are NOT alternating
(else (alternating-signs-in-list? (rest lst))))) ; advance recursion
Alternatively, we can also write the above using just boolean connectors:
(define (alternating-signs-in-list? lst)
(or (empty? lst)
(empty? (rest lst))
(and (not (same-sign? (first lst) (second lst)))
(alternating-signs-in-list? (rest lst)))))
Either way, it works as expected:
(alternating-signs-in-list? '(-1 5 -10))
=> #t
(alternating-signs-in-list? '(5 -17 25))
=> #t
(alternating-signs-in-list? '(-1 -5 6))
=> #f
(alternating-signs-in-list? '(1 -2 -6))
=> #f

Check for ascending order of a list in Racket

I'm new to racket and trying to write a function that checks if a list is in strictly ascending order.
'( 1 2 3) would return true
'(1 1 2) would return false (repeats)
'(3 2 4) would return false
My code so far is:
Image of code
(define (ascending? 'list)
(if (or (empty? list) (= (length 'list) 1)) true
(if (> first (first (rest list))) false
(ascending? (rest list)))))
I'm trying to call ascending? recursively where my base case is that the list is empty or has only 1 element (then trivially ascending).
I keep getting an error message when I use check-expect that says "application: not a procedure."
I guess you want to implement a procedure from scratch, and Alexander's answer is spot-on. But in true functional programming style, you should try to reuse existing procedures to write the solution. This is what I mean:
(define (ascending? lst)
(apply < lst))
It's shorter, simpler and easier to understand. And it works as expected!
(ascending? '(1 2 3))
=> #t
(ascending? '(1 1 2))
=> #f
Some things to consider when writing functions:
Avoid using built in functions as variable names. For example, list is a built in procedure that returns a newly allocated list, so don't use it as an argument to your function, or as a variable. A common convention/alternative is to use lst as a variable name for lists, so you could have (define (ascending? lst) ...).
Don't quote your variable names. For example, you would have (define lst '(1 2 3 ...)) and not (define 'lst '(1 2 3 ...)).
If you have multiple conditions to test (ie. more than 2), it may be cleaner to use cond rather than nesting multiple if statements.
To fix your implementation of ascending? (after replacing 'list), note on line 3 where you have (> first (first (rest list))). Here you are comparing first with (first (rest list)), but what you really want is to compare (first lst) with (first (rest lst)), so it should be (>= (first lst) (first (rest lst))).
Here is a sample implementation:
(define (ascending? lst)
(cond
[(null? lst) #t]
[(null? (cdr lst)) #t]
[(>= (car lst) (cadr lst)) #f]
[else
(ascending? (cdr lst))]))
or if you want to use first/rest and true/false you can do:
(define (ascending? lst)
(cond
[(empty? lst) true]
[(empty? (rest lst)) true]
[(>= (first lst) (first (rest lst))) false]
[else
(ascending? (rest lst))]))
For example,
> (ascending? '(1 2 3))
#t
> (ascending? '(1 1 2))
#f
> (ascending? '(3 2 4))
#f
If you write down the properties of an ascending list in bullet form;
An ascending list is either
the empty list, or
a one-element list, or
a list where
the first element is smaller than the second element, and
the tail of the list is ascending
you can wind up with a pretty straight translation:
(define (ascending? ls)
(or (null? ls)
(null? (rest ls))
(and (< (first ls) (first (rest ls)))
(ascending? (rest ls)))))
This Scheme solution uses an explicitly recursive named let and memoization:
(define (ascending? xs)
(if (null? xs) #t ; Edge case: empty list
(let asc? ((x (car xs)) ; Named `let`
(xs' (cdr xs)) )
(if (null? xs') #t
(let ((x' (car xs'))) ; Memoization of `(car xs)`
(if (< x x')
(asc? x' (cdr xs')) ; Tail recursion
#f)))))) ; Short-circuit termination
(display
(ascending?
(list 1 1 2) )) ; `#f`

Finding the difference in an arithmetic progression in Lisp

I am totally new to Lisp.
How to find the difference between elements in an arithmetic progression series?
e.g.
(counted-by-N '(20 10 0))
Return -10
(counted-by-N '(20 10 5))
(counted-by-N '(2))
(counted-by-N '())
Returns Nil
In Python/C and other languages, it is very straightforward... Kinda stuck here in Lisp.
My pseudo algorithm would be something like this:
function counted-by-N(L):
if len(L) <= 1:
return Nil
else:
diff = L[second] - L[first]
for (i = second; i < len(L) - 1; i++):
if L[i+1] - L[i] != diff
return Nil
return diff
Current work:
(defun count-by-N (L)
(if (<= (length L) 1) Nil
(
(defvar diff (- (second L) (first L)))
; How to do the loop part?
))
)
(flet ((by-n (list &aux
(e1 (first list))
(e2 (second list))
(difference (and e1 e2 (- e2 e1))))
(and difference
(loop for (one two) on list
while (and one two)
when (/= (- two one) difference)
do (return-from by-n nil)))
difference))
(by-n '(20 10 0)))
or
(flet ((by-n (list &aux
(e1 (first list))
(e2 (second list))
(difference (and e1 e2 (- e2 e1))))
(when difference
(loop for (one two) on list
while (and one two)
when (/= (- two one) difference)
do (return-from by-n nil))
difference)))
(by-n '(20 10 0)))
As far as you said on the second answer the best choice you have to do this example is implement it recursively.
Example Using List Processing (good manners)
That way, you have some ways to do this example on the recursively and simple way:
(defun count-by-N-1 (lst)
(if (equal NIL lst)
NIL
(- (car (cdr lst)) (car lst))
)
(count-by-N-1 (cdr lst))
)
On this first approach of the function count-by-N-1 I am using the simple car and cdr instructions to simplify the basics of Common Lisp List transformations.
Example Using List Processing Shortcuts (best implementation)
However you can resume by using some shortcuts of the car and cdr instructions like when you want to do a a car of a cdr, like I did on this example:
(defun count-by-N-2 (lst)
(if (equal NIL lst)
NIL
(- (cadr lst) (car lst))
)
(count-by-N-2 (cdr lst))
)
If you have some problems to understand this kind of questions using basic instructions of Common Lisp List transformation as well as car and cdr, you still can choose the first, second and rest approach. However I recommend you to see some of this basic instructions first:
http://www.gigamonkeys.com/book/they-called-it-lisp-for-a-reason-list-processing.html
Example Using Accessors (best for understand)
(defun count-by-N-3 (lst)
(if (equal NIL lst)
NIL
(- (first (rest lst)) (first lst))
)
(count-by-N-3 (rest lst))
)
This last one, the one that I will explain more clearly since it is the most understandable, you will do a recursion list manipulation (as in the others examples), and like the others, until the list is not NIL it will get the first element of the rest of the list and subtract the first element of the same list. The program will do this for every element till the list is "clean". And at last returns the list with the subtracted values.
That way if you read and study the similarities between using first, second and rest approach against using car and cdr, you easily will understand the both two first examples that I did put here.
Here is my final answer of this question which uses recursion:
(defun diff (N)
(- (second N) (first N))
)
(defun count-by-N (L)
(cond
((null L) nil)
((= (length L) 1) nil)
((= (length L) 2) (diff L))
((= (diff L) (diff (rest L))) (count-by-N (rest L)))
(T nil)
)
)

Overloaded function failing giving Compiler recursion error

With the following code, I get #<CompilerException java.lang.UnsupportedOperationException: Can only recur from tail position (NO_SOURCE_FILE:4)> despite the fact that all recurs are in tail positions. If I remove the recur from the one-argument version, it stops complaining. Why is this happening?
(defn remove-duplicates "Removes duplicate elements of lst.
For example, given (1 2 3 1 4 1 2), remove-duplicates returns a sequence
containing the elements (1 2 3 4), in some order."
[lst] (recur (rest lst) (set (first lst)))
[lst uniques] (cond (zero? (count lst)) uniques
:else (cond
(some (partial = (first lst)) uniques)
(recur (rest lst) uniques)
:else
(recur (rest lst) (first lst)))))
You haven't split up the multi-arity bodies right. Should read (defn foo ([x] (...)) ([x y] (...))). This causes the compiler to think you're doing totally different stuff, which probably accounts for your issue.
First of all: you know that all you want is (def remove-duplicates set) or -- if you want a vector -- (def remove-duplicates-vec (comp vec set)), right?
Five things here:
As amalloy noticed, you should've added parens
As kotarak noticed, you can't recur between arities
You can't call (set (first lst)) because set wants coll. If you want, do something like (set (vector (first [1 2 3 2 3]))) but this is neither pretty nor idiomatic
Doing (cond pred1 code1 :else (cond pred2a code2a :else code2b)) could be made simplier: (cond pred1 code1 pred2a code2a :else code2b) -- what you did is treated cond macro as if it were if (which is a built-in as far as I know)
Your last tail-call is also wrong. Assume we've started with [1 2 3 2 1]
When you call it first you have following arguments: ([2 3 2 1] #{1}) (I've skipped the boring part)
Then you have last predicate true, so you go with ([3 2 1] 2) and this is obviously wrong because you wanted ([3 2 1] #{1 2}). You probably want to call (recur (rest lst) (conj uniques (first lst)))
Summing up:
(defn remove-duplicates
([lst] (remove-duplicates (rest lst) #{(first coll)}))
([lst uniques]
(cond
(zero? (count lst)) uniques
(some (partial = (first lst)) uniques)
(recur (rest lst) uniques)
:else
(recur (rest lst) (conj uniques (first lst))))))

Resources