I'm trying to use recursion in the list and I need to go through all elements. Here is my code:
(define compare
(lambda (ls pred?)
(if (null? list)
#f
(pred? (list-ref ls (- (length ls) 2)) (list-ref ls (- (length ls) 1))))))
But it works only with last two elements. Result should be like this:
(compare '(1 2 3 4 5) <) -> #t
(compare '(1 2 8 4 5) <) -> #f
Do you have any idea what I should do?
You're not using recursion anywhere in the code. In fact, it has errors and I don't think you tested it thoroughly. For example:
The if condition should be (null? ls)
Using list-ref is not the way to go when traversing a list in Scheme, for that in general you want to use recursion, car, cdr, etc.
Again, where is the recursive call? compare should be called at some point!
I believe this is what you intended, it's not recursive but it's the simplest way to implement the procedure:
(define (compare ls pred?)
(apply pred? ls))
Because this looks like homework I can only give you some hints for solving the problem from scratch, without using apply. Fill-in the blanks:
(define (compare ls pred?)
(if <???> ; special case: if the list is empty
<???> ; then return true
(let loop ((prev <???>) ; general case, take 1st element
(ls <???>)) ; and take the rest of the list
(cond (<???> ; again: if the list is empty
<???>) ; then return true
(<???> ; if pred? is false for `prev` and current element
<???>) ; then return false
(else ; otherwise advance the recursion
(loop <???> <???>)))))) ; pass the new `prev` and the rest of the list
Notice that I used a named let for implementing the recursion, so loop is the recursive procedure here: you can see that loop is being called inside loop. Alternatively you could've defined a helper procedure. I had to do this for taking into account the special case where the list is initially empty.
The recursion works like this for the general case: two parameters are required, prev stores the previous element in the list and ls the rest of the list. at each point in the traversal we check to see if the predicates is false for the previous and the current element - if that is the case, then we return false. If not, we continue the recursion with a new prev (the current element) and the rest of the list. We keep going like this until the list is empty and only then we return true.
Related
Note: I am doing this for homework. I'm not looking for the algorithm to solve my problem, just trying to understand how Scheme works.
I'm new to scheme and trying to write a small program to find the smallest item in a list. The program is working in the since that it is finding the correct answer (so the logic is somewhat sound), but I only know this because an error is coming up that it's trying to treat my answer as a function and call it.
(DEFINE (startmin mylist)
(
(repeatmin (CAR mylist) (CDR mylist))
))
(DEFINE (repeatmin curmin mylist)
(
(IF (NULL? mylist) ;If the list is empty
;This is where I'm at a loss. I want a way for this value to be
;sent out once the list is empty
curmin ;return the current minimum
(IF (< curmin (CAR mylist)) ;if the current minimum is less than the head of the list
(repeatmin curmin (CDR mylist)) ;recurse with curmin
(repeatmin (CAR mylist) (CDR mylist)) ;otherwise recurse with the head of the list.
)
)
))
I'm really at a loss of how I get the value, once found, back out of the recursion as it keeps trying to treat the value as a function.
Your parentheses are off. If you write
((if ...))
it means that the result from if is a function that immediately should be called once the value is cmoputed. It seems like you are using parentheses as if they are blocks, like {} in C, but they are not. In fact (begin ...) is a block in Scheme. And of course a function, let and cond terms have implicit begin.. Thus
(define (func . args)
(begin
x
y))
Is the same as
(define (func . args)
x
y)
Also please format your code correctly. Indentation helps you read the code and the nesting. I really don't pay attention to the parentheses, just the position which is crucial. Choose an editor that does this for you. Eg. DrRacket is a nice one I use.
This is extremely easy if I can use an array in imperative language or map (tree-structure) in C++ for example. In scheme, I have no idea how to start this idea? Can anyone help me on this?
Thanks,
Your question wasn't very specific about what's being counted. I will presume you want to create some sort of frequency table of the elements. There are several ways to go about this. (If you're using Racket, scroll down to the bottom for my preferred solution.)
Portable, pure-functional, but verbose and slow
This approach uses an association list (alist) to hold the elements and their counts. For each item in the incoming list, it looks up the item in the alist, and increments the value of it exists, or initialises it to 1 if it doesn't.
(define (bagify lst)
(define (exclude alist key)
(fold (lambda (ass result)
(if (equal? (car ass) key)
result
(cons ass result)))
'() alist))
(fold (lambda (key bag)
(cond ((assoc key bag)
=> (lambda (old)
(let ((new (cons key (+ (cdr old) 1))))
(cons new (exclude bag key)))))
(else (let ((new (cons key 1)))
(cons new bag)))))
'() lst))
The incrementing is the interesting part. In order to be pure-functional, we can't actually change any element of the alist, but instead have to exclude the association being changed, then add that association (with the new value) to the result. For example, if you had the following alist:
((foo . 1) (bar . 2) (baz . 2))
and wanted to add 1 to baz's value, you create a new alist that excludes baz:
((foo . 1) (bar . 2))
then add baz's new value back on:
((baz . 3) (foo . 1) (bar . 2))
The second step is what the exclude function does, and is probably the most complicated part of the function.
Portable, succinct, fast, but non-functional
A much more straightforward way is to use a hash table (from SRFI 69), then update it piecemeal for each element of the list. Since we're updating the hash table directly, it's not pure-functional.
(define (bagify lst)
(let ((ht (make-hash-table)))
(define (process key)
(hash-table-update/default! ht key (lambda (x) (+ x 1)) 0))
(for-each process lst)
(hash-table->alist ht)))
Pure-functional, succinct, fast, but non-portable
This approach uses Racket-specific hash tables (which are different from SRFI 69's ones), which do support a pure-functional workflow. As another benefit, this version is also the most succinct of the three.
(define (bagify lst)
(foldl (lambda (key ht)
(hash-update ht key add1 0))
#hash() lst))
You can even use a for comprehension for this:
(define (bagify lst)
(for/fold ((ht #hash()))
((key (in-list lst)))
(hash-update ht key add1 0)))
This is more a sign of the shortcomings of the portable SRFI 69 hashing library, than any particular failing of Scheme for doing pure-functional tasks. With the right library, this task can be implemented easily and functionally.
In Racket, you could do
(count even? '(1 2 3 4))
But more seriously, doing this with lists in Scheme is much easier that what you mention. A list is either empty, or a pair holding the first item and the rest. Follow that definition in code and you'll get it to "write itself out".
Here's a hint for a start, based on HtDP (which is a good book to go through to learn about these things). Start with just the function "header" -- it should receive a predicate and a list:
(define (count what list)
...)
Add the types for the inputs -- what is some value, and list is a list of stuff:
;; count : Any List -> Int
(define (count what list)
...)
Now, given the type of list, and the definition of list as either an empty list or a pair of two things, we need to check which kind of list it is:
;; count : Any List -> Int
(define (count what list)
(cond [(null? list) ...]
[else ...]))
The first case should be obvious: how many what items are in the empty list?
For the second case, you know that it's a non-empty list, therefore you have two pieces of information: its head (which you get using first or car) and its tail (which you get with rest or cdr):
;; count : Any List -> Int
(define (count what list)
(cond [(null? list) ...]
[else ... (first list) ...
... (rest list) ...]))
All you need now is to figure out how to combine these two pieces of information to get the code. One last bit of information that makes it very straightforward is: since the tail of a (non-empty) list is itself a list, then you can use count to count stuff in it. Therefore, you can further conclude that you should use (count what (rest list)) in there.
In functional programming languages like Scheme you have to think a bit differently and exploit the way lists are being constructed. Instead of iterating over a list by incrementing an index, you go through the list recursively. You can remove the head of the list with car (single element), you can get the tail with cdr (a list itself) and you can glue together a head and its tail with cons. The outline of your function would be like this:
You have to "hand-down" the element you're searching for and the current count to each call of the function
If you hit the empty list, you're done with the list an you can output the result
If the car of the list equals the element you're looking for, call the function recursively with the cdr of the list and the counter + 1
If not, call the function recursively with the cdr of the list and the same counter value as before
In Scheme you generally use association lists as an O(n) poor-man's hashtable/dictionary. The only remaining issue for you would be how to update the associated element.
I am writing a program in Scheme that receives one list with numbers and two empty lists. I would like that the positive numbers are joined to one list, while the negative numbers are put in another list. At the end I would like to return the join of both lists. I am using for this purpose append like this:
(define (joinLists listInic list1 list2)
(if (empty? listInic)
(append list1 list2)
(begin
(if (> (car listInic) 0)
(append list1 (car listInic))
(append list2 (car listInic))
)
(joinLists (cdr listInic) list1 list2))))
but when I run it with some data like:
(joinLists '(4 5 -5 -4) '() '())
it always returns the empty list ()
what am I doing wrong?
The way you're using append is wrong. Sure, we can write this:
(append list1 (list (car listInic))) ; second argument should be a list
… but the list1 parameter is not being modified in-place, instead a new list is created - and given that you didn't assign it or pass it around as a a parameter, then the new list is lost - that's why you're always getting an empty list as a result, the list parameters were never modified. We have to do something like this:
(define (joinLists listInic list1 list2)
(cond ((empty? listInic)
(list list1 list2))
((positive? (car listInic))
(joinLists (cdr listInic) (cons (car listInic) list1) list2))
(else
(joinLists (cdr listInic) list1 (cons (car listInic) list2)))))
Some points to consider:
It's better to use cond when we have multiple conditions, instead of nesting ifs and begins
Use positive? to test if a number is greater than zero
Pass the results around as parameters, as mentioned above, simply appending them (or consign them, or whatever) won't modify lists in-place
Use cons whenever possible, instead of append - it's much cheaper, because it adds elements at the head of the list, whereas append traverses the whole list and creates a new list, and besides its last argument should also be a list, for building a proper list
Regarding the last point, if you absolutely have to preserve the original order from the input list, even so it would be better to use cons and then reverse the output lists at the end - one again, avoiding append. For instance, here's the output for the sample input:
(joinLists '(4 5 -5 -4) '() '())
=> '((5 4) (-4 -5))
append does not change the value of the list, it produces a new list with the given item appended. Since you don't actually use the value produced by append, your use of append has no effect at all. As a general rule of thumb using begin only makes sense when the functions you're calling in it have side-effects, which append does not.
What you should do is pass the result of the append as an argument to the recursive call to joinLists.
I'm newbie in Scheme and find out that if I change a list with set-car!/set-cdr! (even locally) the parent list is modified too. This is an example what I mean:
(define my-list '(1 2 3 4 5)) ; Original list
(define (function list) ; Some example function
(let ((copy list))
(set-car! copy 'new)
(display copy)
)
(function my-list); will display (new 2 3 4 5)
my-list; but the original is changed "forever" and will be also '(new 2 3 4 5)
My question is:
Is there a way to make a copy of the original list and work only on it, so at the end the original not to be changed?
Your code (let ((copy list)) allows list to be accessed through the name copy. So when you set-car! copy, you are actually set-car!'ing the original list.
The phenomenon of mutation in lisp like languages is a little confusing at first.
Mutation is to be avoided usually, for the reasons you have discovered. Parts of lists and things a floating around. This is because internally each node in a list has two parts - the car is it's value which may point to another list, and it's cdr is the part that follows it - usually this is a lit of things similar to the value in car.
This solves your problem using SRFI1's list-copy function
(let ((copy (list-copy list)))
Here is one way to copy a list (make a new list). This code is not really complete. When we look at it internally it adds pieces of a list in each recursive call. Where do the pieces of each new list-section come from? The cdr is generated with the call (list-copy (cdr list)), while the car is simply taken - not copied! - from the other list.
(define (list-copy list)
(if (null? list) '() (cons (car list) (list-copy (cdr list)))))
The result for you when experimenting, was that the car's of your list copy where borrowed from my-list.
Here is a more proper version:
(define (full-copy list)
(if (null? list)
'()
(if (list? list)
(cons (full-copy (car list)) (full-copy (cdr list)))
list)))
Only the code for the car has changed. Now, the car is reconstructed to. The only parts that are borrowed are the numbers (so this copy is not okay when the numbers are instead something more special). I'm not sure how the srfi1 version works.
The let statement only ever binds one identifier to an object - the object is not copied, you simply have another way to access it. So any changes (use of mutation, as in functions that end in "!") will affect both.
I suggest that when you're learning Scheme or Racket, you avoid all the ! functions such as set-car!, set-cdr!, and set!.
Instead of mutating things, try to think in terms of creating a new thing from the old thing(s).
For instance if you have a list and want something new at the start:
;; Return a new list with `x` replacing the head of the list `xs`.
(define (replace-head xs x) ; list? any? -> list?
(cons x (cdr xs)))
;; Using it:
(replace-head '(1 2 3 4 5) 100)
; => '(100 2 3 4 5)
p.s. A version of replace-head that can handle xs being empty could be:
(define (replace-head xs x) ; list? any? -> list?
(cond [(empty? xs) (list x)]
[else (cons x (cdr xs))]))
(replace-head '(1 2 3 4 5) 100)
; => '(100 2 3 4 5)
(replace-head '() 100)
; => '(100)
You also might find it helpful to look at How to Design Programs, for examples of good ways to design and think in Scheme or Racket.
I am currently attempting to resolve a question in a practice mid-term. The question asks for me to write an expression to append two lists (let us call them list1 and list2), and list2 must be appended to the end of list1. The function append cannot be used at any point in this. What I may use is cons, filter, accumulate, map, list-ref, and inumerate-interval. I have attempted various forms of getting to the solution, such as
(cons list1 list2)
(filter list? (map list (cons list1 list2)))
(list list1 list2)
(map list (list list1 list2))
I have spent 2 days attempting to find a solution to no avail. If anyone is able to guide me in the right direction, or even provide me with some form of assistance, I would be grateful.
Also, I apologize if there is some protocol that I am following incorrectly for the code formatting or the mannerisms in asking the question, as I am new to the site. Thank you.
Because this is homework, I can't give you a straight answer. Instead, I'll give you some hints, you can find the answer to your own question filing-in the blanks. This is the standard way to implement append:
(define (my-append l1 l2)
(cond (<???> ; if the first list is null
<???>) ; then return the second list
(<???> ; if the second list is null
<???>) ; then return the first list
(else ; otherwise `cons`
(cons <???> ; the first element of the first list
(my-append <???> l2))))) ; process the rest of the first list
The above solution uses cond, null?, cons, car and cdr. If you can't use any of those and you're restricted to the procedures in the question, try this instead (assuming accumulate is defined as a fold to the right):
(define (my-append l1 l2)
(accumulate
<???> ; what should be used for sticking list elements together?
<???> ; what should we return if the list being traversed is empty?
<???>)) ; this is the list that we want to traverse
The above solution only uses accumulate and cons, as requested in the question. The idea is: traverse the first list recreating it element by element, until the list is exhausted - at that point, the next element will be the second list.