Digit to Word conversion in Racket - recursion

I'm trying to write a program that converts lists of digits (1, 2, 3...etc.) to a list of the corresponding words (One, Two, Three...). I wrote a helper function that translates individual digits. It looks like this:
(define (translate num)
(cond [(= num 1) 'One]
[(= num 2) 'Two]
[(= num 3) 'Three]
[(= num 4) 'Four]
[(= num 5) 'Five]
[(= num 6) 'Six]
[(= num 7) 'Seven]
[(= num 8) 'Eight]
[(= num 9) 'Nine]
[(= num 0) 'Zero]))
That function works. My function that I call on a list like '(1 2 3) looks like this:
(define (translate-digits aList)
(cond [(empty? aList) '()]
[else (cons (translate (first aList))
(translate (first (rest aList))))] ))
It is not working. I think it has to do with the cons. But when I test the input '(1 3 5 7) I get '(One . Three). What's going on?

You're not using recursion, you're just calling your translate function twice instead of calling translate-digits and using recursion.
Notice the slight difference:
(define (translate-digits aList)
(cond [(empty? aList) '()]
[else (cons (translate (first aList))
(translate-digits (rest aList)))]))
By calling translate-digits on the rest of the list, you walk down until you hit the empty list and exit out by returning an empty list.

Related

How to return false if the number is not found in the list

So, I am trying to do this hw problem: write a function that takes two arguments, a list and a number, and the function returns the index of the leftmost occurrence of the number in the list. For example:
If '(1 2 3 3 4) and num = 3, then it returns 2
If '(3 2 3 3 4) and num = 3, then it returns 0
I was able to do that part but what if the number was never found? What if I want to return false when num is not found in the list? How do I do that?
Please remember, I am trying to do this in proper recursion, not tail recursion.
Here's my code.
(define (first_elt_occ lst num)
(cond
((null? lst) #f)
((eq? (car lst) num) 0)
(else
(+ 1 (first_elt_occ (cdr lst) num)))))
(first_elt_occ '(1 2 3 3 4) 3) ;2
(first_elt_occ '(3 2 3 3 4) 3) ;0
(first_elt_occ '(1 2 5 4 3) 3) ;4
(first_elt_occ '(1 2 5 4 3) 6) ;Error
;(makes sense because you can't add boolean expression)
Another question I have is, how would I approach this problem, if I was asked to return the index of the rightmost occurrence of the number in a list (proper recursion). For example: '(3 4 5 4 3 7 ), num = 3 returns 4.
Thank you!
As suggested in the comments, this will be easier if we implement the procedure using tail recursion - by the way, tail recursion is "proper recursion", what makes you think otherwise?
By defining a helper procedure called loop and passing the accumulated result in a parameter, we can return either #f or the index of the element:
(define (first_elt_occ lst num)
(let loop ((lst lst) (acc 0))
(cond
((null? lst) #f)
((equal? (car lst) num) acc)
(else (loop (cdr lst) (add1 acc))))))
If, for some bizarre requirement you can't use tail recursion in your solution, it's possible to rewrite you original solution to account for the case when the answer is #f - but this isn't as elegant or efficient:
(define (first_elt_occ lst num)
(cond
((null? lst) #f)
((equal? (car lst) num) 0)
(else
(let ((result (first_elt_occ (cdr lst) num)))
(if (not result) #f (add1 result))))))
Either way, it works as expected:
(first_elt_occ '(1 2 3 3 4) 3) ; 2
(first_elt_occ '(3 2 3 3 4) 3) ; 0
(first_elt_occ '(1 2 5 4 3) 3) ; 4
(first_elt_occ '(1 2 5 4 3) 6) ; #f
I don't recommend actually taking this approach because a normal tail-recursive implementation is a lot more efficient, simpler, and easier to understand, but you can use a continuation to short-circuit unwinding the call stack in the failure case:
(define (first_elt_occ lst num)
(call/cc
(lambda (return)
(letrec ((loop (lambda (lst)
(cond
((null? lst) (return #f))
((= (car lst) num) 0)
(else (+ 1 (loop (cdr lst))))))))
(loop lst)))))
The basic find first occurrence "skeleton" function is
(define (first_elt_occ lst num)
(and (not (null? lst))
(or (equal (car lst) num)
(first_elt_occ (cdr lst) num))))
This does not return index though. How to add it in?
(define (first_elt_occ lst num)
(and (not (null? lst))
(or (and (equal (car lst) num) 0)
(+ 1 (first_elt_occ (cdr lst) num)))))
Does it work? Not if the element isn't there! It'll cause an error then. How to fix that? Change the +, that's how!
(define (first_elt_occ lst num)
(let ((+ (lambda (a b) (if b (+ a b) b))))
(and (not (null? lst))
(or (and (= (car lst) num) 0)
(+ 1 (first_elt_occ (cdr lst) num))))))
And now it works as expected:
> (first_elt_occ '(1 2 3 3 4) 3)
2
> (first_elt_occ '(3 2 3 3 4) 3)
0
> (first_elt_occ '(3 2 3 3 4) 5)
#f
And to get your second desired function, we restructure it a little bit, into
(define (first_elt_occ lst num)
(let ((+ (lambda (a b) ...... )))
(and (not (null? lst))
(+ (and (= (car lst) num) 0)
(first_elt_occ (cdr lst) num)))))
Now, what should that new + be? Can you finish this up? It's straightforward!
It's unclear why you are opposed to tail recursion. You talk about "proper recursion", which is not a technical term anyone uses, but I assume you mean non-tail recursion: a recursive process rather than an iterative one, in SICP terms. Rest assured that tail recursion is quite proper, and in general is preferable to non-tail recursion, provided one does not have to make other tradeoffs to enable tail recursion.
As Óscar López says, this problem really is easier to solve with tail recursion. But if you insist, it is certainly possible to solve it the hard way. You have to avoid blindly adding 1 to the result: instead, inspect it, adding 1 to it if it's a number, or returning it unchanged if it's false. For example, see the number? predicate.

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

Difficulty trying to take the n-th root of a product of n numbers

I'm trying to make a recursive function which takes in a list of n numbers. What this function should do is take the product of the n numbers and then take the nth root. I got the product of the n numbers working but do not know how to implement the nth root.
What I tried doing is implementing the expt x y function but could not get it right in the recursion. Moreover, when trying to implement this function, I also don't know how I will be able to feed the expt function the nth root. (y=1/n).
(define (nth-root-of-product-of-numbers lst)
(cond [(empty? lst) 1]
[else (* (first lst) (nth-root-of-product-of-numbers (rest lst)))]))
So, the above code produces the product on the list of n-numbers correctly, however it does not compensate for the n-th root problem. A sample input would be:
(check-within
(nth-root-of-product-of-numbers (cons 9 (cons 14 (cons 2 empty)))) 6.316359598 0.0001)
You need to calculate the nth-root at the end of the recursion. There are several ways to do this - for example, defining a helper procedure for finding the product and taking the root after calculating it:
(define (nth-root-of-product-of-numbers lst)
(define (product lst)
(cond [(empty? lst) 1]
[else (* (first lst) (product (rest lst)))]))
(expt (product lst) (/ 1 (length lst))))
A more efficient solution would be to write a tail-recursive procedure, and to pass along the number of elements to avoid calculating the length at the end. Here's how, using a named let:
(define (nth-root-of-product-of-numbers lst)
(let loop ((lst lst) (acc 1) (n 0))
(cond [(empty? lst)
(expt acc (/ 1 n))]
[else
(loop (rest lst) (* (first lst) acc) (add1 n))])))
An even more idiomatic solution would be to use built-in procedures to calculate the product:
(define (nth-root-of-product-of-numbers lst)
(expt (apply * lst) (/ 1 (length lst))))
Anyway, it works as expected:
(nth-root-of-product-of-numbers (list 9 14 2))
=> 6.316359597656378

Is there an alternative for "set!" on Scheme

Was wondering if there's an alternative for using set! in scheme/racket.
Working on assignments and we're not allowed to use set!
For one of my functions I have an incrementer
(set! count (+ count 1))
Was wondering how I would change this so that it won't make use of set!
Presumably, the reason you're not allowed to use set! is that you're being asked to solve problems in a functional way, rather than an imperative way. Let me illustrate with two different functions that both determine the length of a list:
#lang racket
(require rackunit)
(define count 0)
(define (imperative-length l)
(cond [(empty? l) count]
[else (set! count (+ 1 count))
(imperative-length (rest l))]))
(check-equal? (imperative-length '(4 3 2 1)) 4)
(define (functional-length l)
(cond [(empty? l) 0]
[else (+ 1 (functional-length (rest l)))]))
(check-equal? (functional-length '(4 3 2 1)) 4)
;; what happens if we try calling imperative-length again?
(check-equal? (imperative-length '(4 3 2 1)) 4)
;; oh no!
;; what happens if we try calling functional-length again?
(check-equal? (functional-length '(4 3 2 1)) 4)
;; yep, works fine.
Both of these functions work fine, but the functional one can be called repeatedly. But! But! you might say, I just need to remember to set the counter back to zero, or to put the binding of count inside the function. This is true, but in general, functional solutions don't require the programmer to worry about this kind of interaction at all.
So, what does this mean for you? It probably means that you need to pass the count along as another argument. Just a guess.
set! is never needed. Imagine you have this program:
(define (count lst)
(define num 0)
(define (helper lst)
(when (not (null? lst))
(set! num (+ num 1))
(helper (cdr lst))))
(helper lst)
num)
This is almost Fortran with lisp syntax. How would this be done witout set!. One way is by using boxes:
(define (count lst)
(define num (list 0))
(define (helper lst)
(when (not (null? lst))
(set-car! num (+ (car num) 1))
(helper (cdr lst))))
(helper lst)
(car num))
As explained in the SICP videos when you introduce one mutation you sort of can use that to do all types of mutation. As trivia this is a transformation that often is done by Scheme compilers so in many cases the implementations base language has set-car! and not set!. How about doing it without mutation? The trick is to shadow the binding:
(define (count lst)
(define (helper num lst)
(if (not (null? lst))
(helper (+ num 1) (cdr lst))
num))
(helper 0 lst))
This actually got simpler. Imagine you only need to update some of the variables, then you just recurse with the same ones in the other places.

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`

Resources