(EDIT: I'm not going to worry about TCO yet)
I'm (finally getting around to) learning Lisp. I'm trying to write my own (naive-ish) function to flatten a list. I'm starting with the simpler cases and will build it up to handle more complex cases if it doesn't work. Unfortunately right now, I'm getting an infinite loop and can't quite figure out why.
I also don't know how to use any debugging methods in lisp so if you could point me in that direction, too I'd appreciate it.
(defun flattenizer (lst)
(if (listp (car lst))
(flattenizer (car lst))
(if (null lst)
nil
(cons (car lst) (flattenizer (cdr lst))))))
final code:
(defun flattenizer (lst)
(cond
((null lst) nil)
( (consp (car lst))
(nconc (flattenizer (car lst)) (flattenizer (cdr lst)) ))
(T (cons (car lst) (flattenizer (cdr lst))))))
tests:
* (flattenizer '((1 2) (3 4)))
(1 2 3 4)
* (flattenizer '(1 (2 3) (4 5)))
(1 2 3 4 5)
* (flattenizer '((1 2) 3 (4 5) 6))
(1 2 3 4 5 6)
* (flattenizer '(1 2 3 4))
(1 2 3 4)
(listp NIL) returns T, and so does (listp (car NIL)), so when you hit the end-of-list and recurse on NIL, looping happens.
You need to change the order of your tests, testing for the (null lst) first, to avoid the looping. Better re-write it with cond for that. It's easier to change the ordering of tests, with cond.
Then you'll notice that for some reason you only flatten the first element in your argument list, ever. What about (3 4) in ((1 2) (3 4)) etc.? We should really somehow combine the results of flattening the car with the results of flattening the cdr.
If the result of flattening a list is a list, then we will need to combine the two resulting lists. Also, since we will be combining lists, if we encounter an atom we will have to produce a list, as the result of flattening that atom.
NIL is somewhat "strange" in Common Lisp for a mix of practical and historical reasons. For example:
NIL is a symbol: (symbolp NIL) ==> T
NIL is a list: (listp NIL) ==> T
NIL is not a cons cell: (consp NIL) ==> NIL
but you can take car/cdr of it anyway: (car NIL) ==> NIL and (cdr NIL) ==> NIL
In your code calling recursively for (car x) when (listp (car x)) is causing infinite recursion because NIL is a list and its car is itself.
Debugging using SBCL.
Tell SBCL you want debug:
* (proclaim '(optimize (debug 3)))
Your code:
* (defun flattenizer (lst)
(if (listp (car lst))
(flattenizer (car lst))
(if (null lst)
nil
(cons (car lst) (flattenizer (cdr lst))))))
FLATTENIZER
Stepping it with STEP
* (step (flattenizer '(1 (2 3) 4)))
; Evaluating call:
; (FLATTENIZER '(1 (2 3) 4))
; With arguments:
; (1 (2 3) 4)
next step
1] step
; Evaluating call:
; (FLATTENIZER (CDR LST))
; With arguments:
; ((2 3) 4)
next step
1] step
; Evaluating call:
; (FLATTENIZER (CAR LST))
; With arguments:
; (2 3)
next step
1] step
; Evaluating call:
; (FLATTENIZER (CDR LST))
; With arguments:
; (3)
next step
1] step
; Evaluating call:
; (FLATTENIZER (CDR LST))
; With arguments:
; NIL
next step
1] step
; Evaluating call:
; (FLATTENIZER (CAR LST))
; With arguments:
; NIL
next step
1] step
; Evaluating call:
; (FLATTENIZER (CAR LST))
; With arguments:
; NIL
Looks like you are in a loop now.
Getting back to the toplevel.
1] top
*
Now check your source code.
Related
I'm trying to write a function that recursively returns the negative values of a list. This is what I have so far:
(defun neg-nums (L)
(if (null L) nil
(let ((X (neg-nums (cdr L))))
(if (< (car L) 0) (append (list (car L)) X)))))
(print (neg-nums (list 1 -2 3 -4)))
I tried the let function outside of the recursion, and it works fine, so I know its something to do with trying to make it recursive. right now, it just outputs NIL when it should output (-2 -4).
(PS, the print function is so when I load it as a file, I can see the result right away.)
Any help would be appreciated.
Apologies, I just realized that I needed an extra X in the last line. the correct answer is this:
(defun neg-nums (L)
(if (null L) nil
(let ((X (neg-nums (cdr L))))
(if (< (car L) 0) (append (list (car L)) X) X))))
(print (neg-nums (list 1 -2 3 -4)))
i am trying to write a function in Scheme that takes in a list and an integer and outputs the same list minus all the members less than the integer... please help. I seem to be unable to add the numbers into a new list that can be outputed.
(define result '())
(display result)
(define nums-less-than-x
(lambda (lst x)
(define impl
(lambda (l1 b result)
(if (null? l1) result
(begin (if (> b (car l1))
(begin (cons (car l1) result)
;(display result)(newline)(newline)
(display (car l1) )(newline))
)
(impl (cdr l1) b result)
))
))
(impl lst x result)
))
(display (show-up '(4 6 3 -8 3 4) 5))
The code juss displays (), an empty list like that, when I run
(display (num-less-than-x '(some list) x))
Your result is never updated. usually I would expect that only when the element is not being a part of the result and otherwise a recursion like:
(impl (cdr l1) b (cons (car l1) result))
I notice that you have put debug output as the last expression in a begin, eg.
(begin
expression-that-does-something
(display ...)
(newline))
Note that the expressions result is not the result, but the result from the newline, typically some undefined value. You need to put your debug stuff first then as the tail the expression your function should return. Alternatively you could make a debug function:
(define (debug expr)
(display expr)
(newline)
expr))
My understanding is that you want the procedure to return the result, not to display it, which is the right way to do it:
(define show-up
(lambda (lst mx)
(if (null? lst)
lst
(let ((c (car lst)))
(if (> c mx)
(show-up (cdr lst) mx)
(cons c (show-up (cdr lst) mx)))))))
Testing:
> (show-up '(4 6 3 -8 3 4) 5)
'(4 3 -8 3 4)
When programming in a functional style, we try to use existing procedures to solve a problem. With that in mind, the preferred solution would be:
(define (show-up-to-n lst x)
(filter (lambda (n) (< n x))
lst))
Also notice that in truly functional code we avoid at all costs procedures that modify state (such as set!), it's a better idea to create a new list with the result.
The problem is to:
Write a function (encode L) that takes a list of atoms L and run-length encodes the list such that the output is a list of pairs of the form (value length) where the first element is a value and the second is the number of times that value occurs in the list being encoded.
For example:
(encode '(1 1 2 4 4 8 8 8)) ---> '((1 2) (2 1) (4 2) (8 3))
This is the code I have so far:
(define (encode lst)
(cond
((null? lst) '())
(else ((append (list (car lst) (count lst 1))
(encode (cdr lst)))))))
(define (count lst n)
(cond
((null? lst) n)
((equal? (car lst) (car (cdr lst)))
(count (cdr lst) (+ n 1)))
(else (n)))))
So I know this won't work because I can't really think of a way to count the number of a specific atom in a list effectively as I would iterate down the list. Also, Saving the previous (value length) pair before moving on to counting the next unique atom in the list. Basically, my main problem is coming up with a way to keep a count of the amount of atoms I see in the list to create my (value length) pairs.
You need a helper function that has the count as additional argument. You check the first two elements against each other and recurse by increasing the count on the rest if it's a match or by consing a match and resetting count to 1 in the recursive call.
Here is a sketch where you need to implement the <??> parts:
(define (encode lst)
(define (helper lst count)
(cond ((null? lst) <??>)
((null? (cdr lst)) <??>))
((equal? (car lst) (cadr lst)) <??>)
(else (helper <??> <??>))))
(helper lst 1))
;; tests
(encode '()) ; ==> ()
(encode '(1)) ; ==> ((1 1))
(encode '(1 1)) ; ==> ((1 2))
(encode '(1 2 2 3 3 3 3)) ; ==> ((1 1) (2 2) (3 4))
Using a named let expression
This technique of using a recursive helper procedure with state variables is so common in Scheme that there's a special let form which allows you to express the pattern a bit nicer
(define (encode lst)
(let helper ((lst lst) (count 1))
(cond ((null? lst) <??>)
((null? (cdr lst)) <??>))
((equal? (car lst) (cadr lst)) <??>)
(else (helper <??> <??>)))))
Comments on the code in your question: It has excess parentheses..
((append ....)) means call (append ....) then call that result as if it is a function. Since append makes lists that will fail miserably like ERROR: application: expected a function, got a list.
(n) means call n as a function.. Remember + is just a variable, like n. No difference between function and other values in Scheme and when you put an expression like (if (< v 3) + -) it needs to evaluate to a function if you wrap it with parentheses to call it ((if (< v 3) + -) 5 3); ==> 8 or 2
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`
First off, this is homework, but I am simply looking for a hint or pseudocode on how to do this.
I need to sum all the items in the list, using recursion. However, it needs to return the empty set if it encounters something in the list that is not a number. Here is my attempt:
(DEFINE sum-list
(LAMBDA (lst)
(IF (OR (NULL? lst) (NOT (NUMBER? (CAR lst))))
'()
(+
(CAR lst)
(sum-list (CDR lst))
)
)
)
)
This fails because it can't add the empty set to something else. Normally I would just return 0 if its not a number and keep processing the list.
I suggest you use and return an accumulator for storing the sum; if you find a non-number while traversing the list you can return the empty list immediately, otherwise the recursion continues until the list is exhausted.
Something along these lines (fill in the blanks!):
(define sum-list
(lambda (lst acc)
(cond ((null? lst) ???)
((not (number? (car lst))) ???)
(else (sum-list (cdr lst) ???)))))
(sum-list '(1 2 3 4 5) 0)
> 15
(sum-list '(1 2 x 4 5) 0)
> ()
I'd go for this:
(define (mysum lst)
(let loop ((lst lst) (accum 0))
(cond
((empty? lst) accum)
((not (number? (car lst))) '())
(else (loop (cdr lst) (+ accum (car lst)))))))
Your issue is that you need to use cond, not if - there are three possible branches that you need to consider. The first is if you run into a non-number, the second is when you run into the end of the list, and the third is when you need to recurse to the next element of the list. The first issue is that you are combining the non-number case and the empty-list case, which need to return different values. The recursive case is mostly correct, but you will have to check the return value, since the recursive call can return an empty list.
Because I'm not smart enough to figure out how to do this in one function, let's be painfully explicit:
#lang racket
; This checks the entire list for numericness
(define is-numeric-list?
(lambda (lst)
(cond
((null? lst) true)
((not (number? (car lst))) false)
(else (is-numeric-list? (cdr lst))))))
; This naively sums the list, and will fail if there are problems
(define sum-list-naive
(lambda (lst)
(cond
((null? lst) 0)
(else (+ (car lst) (sum-list-naive (cdr lst)))))))
; This is a smarter sum-list that first checks numericness, and then
; calls the naive version. Note that this is inefficient, because the
; entire list is traversed twice: once for the check, and a second time
; for the sum. Oscar's accumulator version is better!
(define sum-list
(lambda (lst)
(cond
((is-numeric-list? lst) (sum-list-naive lst))
(else '()))))
(is-numeric-list? '(1 2 3 4 5))
(is-numeric-list? '(1 2 x 4 5))
(sum-list '(1 2 3 4 5))
(sum-list '(1 2 x 4 5))
Output:
Welcome to DrRacket, version 5.2 [3m].
Language: racket; memory limit: 128 MB.
#t
#f
15
'()
>
I suspect your homework is expecting something more academic though.
Try making a "is-any-nonnumeric" function (using recursion); then you just (or (is-any-numeric list) (sum list)) tomfoolery.