How would I go about improving the efficiency (Scheme)? - scheme

I have this code:
(define tree `(A (B (C)) (D (E)) (C (E))))
(define (prog1 graph)
(let ([seen `()])
(define (sub g)
(cond
[(member (car g) seen) `()]
[else
(set! seen (cons (car g) seen))
(cond
[(null? (cdr g)) (list (car g))]
[else
(cons (car g) (map sub (cdr g)))])]))
(delete `() (sub graph))))
(define delete
(lambda (x y)
(if (null? y )
`()
(if (eqv? (car y) x)
(delete x (cdr y))
(cons (car y) (delete x (cdr y)))))))
It prints a connected graph where all the nodes appear once.
Running (prog1 tree)
prints: (A (B (C)) (D (E)))
I have looked at various depth-first searches in lisp (something which is similar to what I'm trying to do) and they appear to be much more elegant to this, some using iterative approaches. I am aware that the program isn't very efficient (on huge trees it runs pretty slow) so how would I go about improving the efficiency of this code?
Thanks, James

The member procedure performs an O(n) lookup on lists every time it's invoked. That's not what we want for quickly testing set membership, for that you should use a data structure providing an O(1) complexity for both adding elements and testing element membership in a collection, ideally a Set data structure or in its place a Hash Table. For example, in Racket try replacing these lines (or use the default hash table implementation in your Scheme interpreter):
(let ([seen `()]) => (let ([seen (make-hash)])
[(member (car g) seen) `()] => [(hash-has-key? seen (car g)) '()]
(set! seen (cons (car g) seen)) => (hash-set! seen (car g) 'ok)
Also, in general you want to use quotes in your code: '() instead of quasiquotes: `(), see the links to understand the difference and when it's appropriate to use quasiquoting.
Finally, you can use the built-in remove procedure, there's no need to implement your own delete.

In most cases the bottleneck in this code will not be the tree traversal, but the member lookup. The complexity of your function seems to be roughly O(M*N), where M is the number of distinct nodes and N is the number of total nodes. The reason why M goes into this as a factor is because you're looking up nodes in a linear list, which takes time proportional to the length of the list (which in your case is proportional to the number of distinct nodes).
The way to get rid of the M is to use a more efficient data structure for the lookup. R6RS defines hash tables, for instance.

Related

Scheme: are `letrec` and `letcc` crucial for efficiency?

I am reading The Seasoned Schemer by Friedman and Felleisen, but I am a little uneasy with some of their best practices.
In particular, the authors recommend:
using letrec to remove arguments that do not change for recursive applications;
using letrec to hide and to protect functions;
using letcc to return values abruptly and promptly.
Let's examine some consequences of these rules.
Consider for example this code for computing the intersection of a list of lists:
#lang scheme
(define intersectall
(lambda (lset)
(let/cc hop
(letrec
[[A (lambda (lset)
(cond [(null? (car lset)) (hop '())]
[(null? (cdr lset)) (car lset)]
[else (I (car lset) (A (cdr lset)))]))]
[I (lambda (s1 s2)
(letrec
[[J (lambda (s1)
(cond [(null? s1) '()]
[(M? (car s1) s2) (cons (car s1) (J (cdr s1)))]
[else (J (cdr s1))]))]
[M? (lambda (el s)
(letrec
[[N? (lambda (s)
(cond [(null? s) #f]
[else (or (eq? (car s) el) (N? (cdr s)))]))]]
(N? s)))]]
(cond [(null? s2) (hop '())]
[else (J s1)])))]]
(cond [(null? lset) '()]
[else (A lset)])))))
This example appears in Chapter 13 (not exactly like this: I glued the membership testing code that is defined separately in a previous paragraph).
I think the following alternative implementation, which makes very limited use of letrec and letcc is much more readable and simpler to understand:
(define intersectall-naive
(lambda (lset)
(letrec
[[IA (lambda (lset)
(cond [(null? (car lset)) '()]
[(null? (cdr lset)) (car lset)]
[else (intersect (car lset) (IA (cdr lset)))]))]
[intersect (lambda (s1 s2)
(cond [(null? s1) '()]
[(M? (car s1) s2) (cons (car s1) (intersect (cdr s1) s2))]
[else (intersect (cdr s1) s2)]))]
[M? (lambda (el s)
(cond [(null? s) #f]
[else (or (eq? (car s) el) (M? el (cdr s)))]))]]
(cond [(null? lset) '()]
[else (IA lset)]))))
I am new to scheme and my background is not in Computer Science, but it strikes me that we have to end up with such complex code for a simple list intersection problem. It makes me wonder how people manage the complexity of real-world applications.
Are experienced schemers spending their days deeply nesting letcc and letrec expressions?
This was the motivation for asking stackexchange.
My question is: are Friedman and Felleisen overly complicating this example for education's sake, or should I just get accustomed to scheme code full of letccs and letrecs for performance reasons?
Is my naive code going to be impractically slow for large lists?
I'm not an expert on Scheme implementations, but I have some ideas about what's going on here. One advantage the authors have via their let/cc that you don't have is early termination when it's clear what the entire result will be. Suppose someone evaluates
(intersectall-naive (list big-list
huge-list
enormous-list
gigantic-list
'()))
Your IA will transform this to
(intersect big-list
(intersect huge-list
(intersect enormous-list
(intersect gigantic-list
'()))))
which is reasonable enough. The innermost intersection will be computed first, and since gigantic-list is not nil, it will traverse the entirety of gigantic-list, for each item checking whether that item is a member of '(). None are, of course, so this results in '(), but you did have to walk the entire input to find that out. This process will repeat at each nested intersect call: your inner procedures have no way to signal "It's hopeless, just give up", because they communicate only by their return value.
Of course you can solve this without let/cc, by checking the return value of each intersect call for nullness before continuing. But (a) it is rather pretty to have this check only occur in one direction instead of both, and (b) not all problems will be so amenable: maybe you want to return something where you can't signal so easily that early exit is desired. The let/cc approach is general, and allows early-exit in any context.
As for using letrec to avoid repetition of constant arguments to recursive calls: again, I am not an expert on Scheme implementations, but in Haskell I have heard the guidance that if you are closing over only 1 parameter it's a wash, and for 2+ parameters it improves performance. This makes sense to me given how closures are stored. But I doubt it is "critical" in any sense unless you have a large number of arguments or your recursive functions do very little work: argument handling will be a small portion of the work done. I would not be surprised to find that the authors think this improves clarity, rather than doing it for performance reasons. If I see
(define (f a x y z)
(define (g n p q r) ...)
(g (g (g (g a x y z) x y z) x y z) x y z))
I will be rather less happy than if I see
(define (f a x y z)
(define (g n) ...)
(g (g (g (g a)))))
because I have to discover that actually p is just another name for x, etc., check that the same x, y, and z are used in each case, and confirm that this is on purpose. In the latter case, it is obvious that x continues to have that meaning throughout, because there is no other variable holding that value. Of course this is a simplified example and I would not be thrilled to see four literal applications of g regardless, but the same idea holds for recursive functions.

How to check if a list is even, in

I want to test if a list is even, in . Like (evenatom '((h i) (j k) l (m n o)) should reply #t because it has 4 elements.
From Google, I found how to check for odd:
(define (oddatom lst)
(cond
((null? lst) #f)
((not (pair? lst)) #t)
(else (not (eq? (oddatom (car lst)) (oddatom (cdr lst)))))))
to make it even, would I just swap the car with a cdr and cdr with car?
I'm new to Scheme and just trying to get the basics.
No, swapping the car and cdr won't work. But you can swap the #f and #t.
Also, while the list you gave has 4 elements, what the function does is actually traverse into sublists and count the atoms, so you're really looking at 8 atoms.
You found odd atom using 'Google' and need even atom. How about:
(define (evenatom obj) (not (oddatom obj)))
or, adding some sophistication,
(define (complement pred)
(lambda (obj) (not (pred obj))))
and then
(define evenatom (complement oddatom))
you are mixing a procedure to check if a list has even numbers of elements (not restricted to atoms) and a procedure that checks if there are an even number of atomic elements in the list structure. Example: ((a b) (c d e) f) has an odd number of elements (3) but an even number (6) of atoms.
If you had some marbles, how would you determine if you had an odd or even number of marbles? you could just count them as normal and check the end sum for evenness or count 1,0,1,0 or odd,even,odd,even so that you really didn't know how many marbles I had in the end, only if it's odd or even. Lets do both:
(define (even-elements-by-count x)
(even? (length x)))
(define (even-elements-by-boolean x)
(let loop ((x x)(even #t))
(if (null? x)
even
(loop (cdr x) (not even)))))
now imagine that you had some cups in addition and that they had marbles to and you wondered the same. You'd need to count the elements on the floor and the elements in cups and perhaps there was a cup in a cup with elements as well. For this you should look at How to count atoms in a list structure and use the first approach or modify one of them to update evenness instead of counting.
The equivalent of the procedure you link to, for an even number of atoms, is
(define (evenatom lst)
(cond
((null? lst) #t)
((not (pair? lst)) #f)
(else (eq? (evenatom (car lst)) (evenatom (cdr lst))))))
You need to swap #t and #f, as well as leave out the not clause of the last line.

Another way of writing a mimum value procedure in Scheme?

So if i have the following, which returns the smallest value out of a set of four numbers:
(define (minimum2 a b c d)
(cond ((and (< a b) (< a c) (< a d)) a)
((and (< b c) (< b d)) b)
((< c d) c)
(else d)))
But, I want to write it so that I compare a to b and find the smallest value between those two, then compare c and d, and find the smallest value between those, and then compare those two smallest values together to find the actual minimum. If what I wrote was tough to understand, think of it like a tournament bracket, where a "plays" b, and the winner plays the other winner between c and d. Thank you in advance for the help!
Here's one way to do it:
(define (min4 a b c d)
(define (min2 x y)
(if (< x y) x y))
(min2 (min2 a b) (min2 c d)))
Another way to do it, if you don't want to use an internal function:
(define (min4 a b c d)
(let ((min-ab (if (< a b) a b))
(min-cd (if (< c d) c d)))
(if (< min-ab min-cd) min-ab min-cd)))
Here are two ways to do this. I think that the first, using reduce, is much more idiomatic, but it's not doing the tournament style structure, though it uses the same number of comparisons. The second, which does a tournament style structure, is actually just a special case of a generalized merge-sort. The reason that the number of comparisons is the same is that in the tournament style comparison,
min(a,b,c,d) = min(min(a,b),min(c,d))
and in the reduce formulation,
min(a,b,c,d) = min(min(min(a,b),c),d)
Both require three calls the lowest level min procedure.
A reduce based approach
This solution uses a fold (more commonly called reduce in Lisp languages, in my experience). Scheme (R5RS) doesn't include reduce or fold, but it's easy to implement:
(define (reduce function initial-value list)
(if (null? list)
initial-value
(reduce function (function initial-value (car list))
(cdr list))))
A left-associative fold is tail recursive and efficient. Given a binary function f, an initial value i, and a list [x1,…,xn], it returns f(f(…f(f(i, x1), x2)…), xn-1), xn).
In this case, the binary function is min2. R5R5 actually already includes an n-ary (well, it actually requires at least one arguments, it's at-least-one-ary) min, which means min would already work as a binary function, but then again, if you wanted to use the built in min, you'd just do (min a b c d) in the first place. So, for the sake of completeness, here's a min2 that accepts exactly two arguments.
(define (min2 a b)
(if (< a b)
a
b))
Then our n-ary min* is simply a reduction of min2 over an initial value and a list. We can use the . notation in the argument list to make this a variadic function that requires at least one argument. This means that we can do (min* x) => x, in addition to the more typical many-argument calls.
(define (min* a . rest)
(reduce min2 a rest))
For example:
(min* 4 2 1 3)
;=> 1
A true tournament-style solution based on merge sort
A proper tournament style min is actually isomorphic to merge sort. Merge sort recursively splits a list in half (this can be done in place using the indices of the original list, as opposed to actually splitting the list into new lists), until lists of length one are produced. Then adjacent lists are merged to produce lists of length two. Then, adjacent lists of length two are merged to produce lists of length four, and so on, until there is just one sorted list. (The numbers here don't always work out perfectly if the length of the input list isn't a power of two, but the same principle applies.) If you write an implementation of merge sort that takes the merge function as a parameter, then you can have it return the one element list that contains the smaller value.
First, we need a function to split a list into left and right sides:
(define (split lst)
(let loop ((left '())
(right lst)
(len (/ (length lst) 2)))
(if (< len 1)
(list (reverse left) right)
(loop (cons (car right) left)
(cdr right)
(- len 1)))))
> (split '(1 2 3 4))
((1 2) (3 4))
> (split '(1))
(() (1))
> (split '(1 2 3))
((1) (2 3))
Merge sort is now pretty easy to implement:
(define (merge-sort list merge)
(if (or (null? list) (null? (cdr list)))
list
(let* ((sides (split list))
(left (car sides))
(right (cadr sides)))
(merge (merge-sort left merge)
(merge-sort right merge)))))
We still need the merge procedure. Rather than the standard one that takes two lists and returns a list of their sorted elements, we need one that can take two lists, where each has at most one element, and at most one of the lists may be empty. If either list is empty, the non-empty list is returned. If both lists are non-empty, then the one with the smaller element is returned. I've called it min-list.
(define (min-list l1 l2)
(cond
((null? l1) l2)
((null? l2) l1)
(else (if (< (car l1) (car l2))
l1
l2))))
In this case, you can define min* to make a call to merge-sort, where the merge procedure is min-list. Merge-sort will return a list containing one element, so we need car to take that element from the list.
(define (min* a . rest)
(car (merge-sort (cons a rest) min-list)))
(min* 7 2 3 6)
;=> 2

Sorting algorithm lisp-scheme

I have decided to learn some functional language and I hooked up with the lisp-scheme after all.
I am trying to make a function which checks if a list is sorted, either with lowest first getting higher or vice versa, and if it can be sorted it should return true else false.
This is my first code, working only if the list is increasing (or equal).
(define sorted?
(lambda (lst)
(cond ((empty? lst) #t)
(else (and (<= (car lst) (cadr lst))
(sorted? (cdr lst)))))))
clarification: something like (sorted? '(1 2 3 4 5)) and (sorted? '(5 4 3 2 1)) should return true, else if not sorted false of course.
How am I supposed to think when programming in a functional style? The syntax seems straight-forward but I'm not used to the logic.
Specific implementation
I'd take Óscar López's answer and go one step further:
(define sorted? (lambda (lst)
(letrec ((sorted-cmp
(lambda (lst cmp)
(cond ((or (empty? lst) (empty? (cdr lst)))
#t)
(else (and (cmp (car lst) (cadr lst))
(sorted-cmp (cdr lst) cmp)))))))
(or (sorted-cmp lst <=) (sorted-cmp lst >=)))))
The biggest difference between this version and his is that sorted? now defines Óscar's version as an internal helper function using letrec and calls it both ways.
Functional Thinking
You actually chose a good example for illustrating some aspects of how Scheme views the world, and your implementation was off to a very good start.
One important functional principle involved in the solution to this problem is that anything you could put (**here** more stuff '(1 2 3 4)), you can pass around as an argument to another function. That is, functions are first class in a functional programming language. So the fact that you were using <= in your comparison means that you can pass <= as a parameter to another function that makes a comparison accordingly. Óscar's answer is a great illustration of that point.
Another aspect of this problem that embodies another common functional pattern is a function that consists primarily of a (cond) block. In many functional programming languages (Haskell, ML, OCaml, F#, Mathematica), you get stronger pattern matching abilities than you get, by default in Scheme. So with (cond) in Scheme, you have to describe how to test for the pattern that you seek, but that's usually fairly straightforward (for example the (or (empty? lst) (empty? (cdr lst))) in this implementation.
One final functional programming pattern that I see as well-embodied in this problem is that many functional programming solutions are recursive. Recursion is why I had to use letrec instead of plain ol' let.
Almost anything you can do by operating on the first element (or 2 elements as in this case) and then repeating the operation on the tail (cdr) of the list you do that way. Imperative for- or while-style loops aren't impossible in Scheme (although they are pretty much impossible in pure functional languages such as Haskell), they're slightly out of place in Scheme under many circumstances. But Scheme's flexibility that allows you, as the developer, to make that decision enables important performance or maintainability optimizations in certain circumstances.
Continuing exploration
My first implementation of sorted? for my answer here was going to decide which comparison operator to pass to sorted-cmp based on what it saw in the list. I backed off on that when I spotted that a list could start with two equal numbers '(1 1 2 3 4 5). But as I think more about it, there's definitely a way to track whether you've decided a direction yet and, thus, only have one call required to sorted-cmp. You might consider exploring that next.
You almost got it right, look:
(define sorted?
(lambda (lst)
(cond ((or (empty? lst) (empty? (cdr lst)))
#t)
(else (and (<= (car lst) (cadr lst))
(sorted? (cdr lst)))))))
A little modification in the base case, and you're all set. It's necessary to stop when there's only one element left in the list, otherwise the cadr expression will throw an error.
For the second part of your question: If you want to check if it's sorted using a different criterion, simply pass the comparison function as an argument, like this:
(define sorted?
(lambda (lst cmp)
(cond ((or (empty? lst) (empty? (cdr lst)))
#t)
(else (and (cmp (car lst) (cadr lst))
(sorted? (cdr lst) cmp))))))
(sorted? '(1 2 3 4 5) <=)
> #t
(sorted? '(5 4 3 2 1) >=)
> #t
Now if you want to know if a list is sorted in either ascending order or in descending order:
(define lst '(1 2 3 4 5))
(or (sorted? lst >=) (sorted? lst <=))
> #t
As you can see, functional programming is about defining procedures as generic as possible and combining them to solve problems. The fact that you can pass functions around as parameters helps a great deal for implementing generic functions.
I'm going to take your question to mean, more specifically, "if I already program in an imperative language like C or Java, how do I adjust my thinking for functional programming?" Using your problem as an example, I'm going to spend my Saturday morning answering this question in long form. I'll trace the evolution of a functional programmer through three stages, each a successively higher plane of zen - 1) thinking iteratively; 2) thinking recursively; and 3) thinking lazily.
Part I - Thinking Iteratively
Let's say I'm programming in C and I can't or won't use recursion - perhaps the compiler does not optimize tail recursion, and a recursive solution would overflow the stack. So I start thinking about what state I need to maintain. I imagine a little machine crawling over the input. It remembers if it is searching for an increasing or a decreasing sequence. If it hasn't decided yet, it does so based on the current input, if it can. If it finds input headed in the wrong direction, it terminates with zigzag=true. If it reaches the end of the input, it terminates with zigzag=false.
int
zigzag(int *data, int n)
{
enum {unknown, increasing, decreasing} direction = unknown;
int i;
for (i = 1; i < n; ++i)
{
if (data[i] > data[i - 1]) {
if (direction == decreasing) return 1;
direction = increasing;
}
if (data[i] < data[i - 1]) {
if (direction == increasing) return 1;
direction = decreasing;
}
}
/* We've made it through the gauntlet, no zigzagging */
return 0;
}
This program is typical of C programs: it is efficient but it is difficult to prove that it will do the right thing. Even for this simple example, it's not immediately obvious that this can't get stuck in an infinite loop, or take a wrong turn in its logic somewhere. Of course, it gets worse for more complicated programs.
Part II - Thinking Recursively
I find that the key to writing readable programs in the spirit of functional languages (as opposed to just trying to morph an imperative solution into that language) is to focus on what the program should calculate rather than on how it should do it. If you can do that with enough precision - if you can write the problem out clearly - then most of the time in functional programming, you're almost at the solution!
So let's start by writing out the thing to be calculated in more detail. We want to know if a list zigzags (i.e. decreases at some point, and increases at another). Which lists meet this criterion? Well, a list zigzags if:
it is more than two elements long AND
it initially increases, but then decreases at some point OR
it initially decreases, but then increases at some point OR
its tail zigzags.
It's possible to translate the above statements, more or less directly, into a Scheme function:
(define (zigzag xs)
(and (> (length xs) 2)
(or (and (initially-increasing xs) (decreases xs))
(and (initially-decreasing xs) (increases xs))
(zigzag (cdr xs)))))
Now we need definitions of initially-increasing, initially-decreasing, decreases, and increases. The initially- functions are straightforward enough:
(define (initially-increasing xs)
(> (cadr xs) (car xs)))
(define (initially-decreasing xs)
(< (cadr xs) (car xs)))
What about decreases and increases? Well, a sequence decreases if it is of length greater than one, and the first element is greater than the second, or its tail decreases:
(define (decreases xs)
(letrec ((passes
(lambda (prev rest)
(cond ((null? rest) #f)
((< (car rest) prev)
#t)
(else (passes (car rest) (cdr rest)))))))
(passes (car xs) (cdr xs))))
We could write a similar increases function, but it's clear that only one change is needed: < must become >. Duplicating so much code should make you uneasy. Couldn't I ask the language to make me a function like decreases, but using > in that place instead? In functional languages, you can do exactly that, because functions can return other functions! So we can write a function that implements: "given a comparison operator, return a function that returns true if that comparison is true for any two successive elements of its argument."
(define (ever op)
(lambda (xs)
(letrec ((passes
(lambda (prev rest)
(cond ((null? rest) #f)
((op (car rest) prev)
#t)
(else (passes (car rest) (cdr rest)))))))
(passes (car xs) (cdr xs)))))
increases and decreases can now both be defined very simply:
(define decreases (ever <))
(define increases (ever >))
No more functions to implement - we're done. The advantage of this version over the C version is clear - it's much easier to reason that this program will do the right thing. Most of this program is quite trivial with all the complexity being pushed into the ever function, which is a quite general operation that would be useful in plenty of other contexts. I am sure by searching one could find a standard (and thus more trustworthy) implementation rather than this custom one.
Though an improvement, this program still isn't perfect. There's lots of custom recursion and it's not obvious at first that all of it is tail recursive (though it is). Also, the program retains faint echos of C in the form of multiple conditional branches and exit points. We can get an even clearer implementation with the help of lazy evaluation, and for that we're going to switch languages.
Part III - Thinking Lazily
Let's go back to the problem definition. It can actually be stated much more simply than it was in part II - "A sequence zigzags (i.e. is non-sorted) if it contains comparisons between adjacent elements that go in both directions". I can translate that sentence, more or less directly, into a line of Haskell:
zigzag xs = LT `elem` comparisons && GT `elem` comparisons
Now I need a way to derive comparisons, the list of comparisons of every member of xs with its successor. This is not hard to do and is perhaps best explained by example.
> xs
[1,1,1,2,3,4,5,3,9,9]
> zip xs (tail xs)
[(1,1),(1,1),(1,2),(2,3),(3,4),(4,5),(5,3),(3,9),(9,9)]
> map (\(x,y) -> compare x y) $ zip xs (tail xs)
[EQ,EQ,LT,LT,LT,LT,GT,LT,EQ]
That's all we need; these two lines are the complete implementation -
zigzag xs = LT `elem` comparisons && GT `elem` comparisons
where comparisons = map (\(x,y) -> compare x y) $ zip xs (tail xs)
and I'll note that this program makes just one pass through the list to test for both the increasing and decreasing cases.
By now, you have probably thought of an objection: isn't this approach wasteful? Isn't this going to search through the entire input list, when it only has to go as far as the first change of direction? Actually, no, it won't, because of lazy evaluation. In the example above, it calculated the entire comparisons list because it had to in order to print it out. But if it's going to pass the result to zigzag, it will only evaluate the comparisons list far enough to find one instance of GT and one of LT, and no further. To convince yourself of this, consider these cases:
> zigzag $ 2:[1..]
True
> zigzag 1:[9,8..]
True
The input in both cases is an infinite list ([2,1,2,3,4,5..] and [1,9,8,7,6,5...]). Try to print them out, and they will fill up the screen. But pass them to zigzag, and it will return very quickly, as soon as it finds the first change in direction.
A lot of the difficultly in reading code comes from following multiple branches of control flow. And a lot of those branches are really efforts to avoid calculating more than we need to. But much of the same thing can be achieved with lazy evaluation, allowing the program to be both shorter and truer to the original question.
Try this
(define sorted?
(lambda (l)
(cond ((null? l) #t)
(else (check-asc? (car l) (sorted? (cdr l))
(check-desc? (car l) (sorted? (cdr l))))))
(define check-asc?
(lambda (elt lst)
(cond ((null? lst) #t)
(else (or (< elt (car lst)) (= elt (car lst))) (check-asc? (car lst) (cdr lst))))))
(define check-desc?
(lambda (elt lst)
(cond ((null? lst) #t)
(else (or (< elt (car lst)) (= elt (car lst))) (check-desc? (car lst) (cdr lst))))))
I am a newbie myself. I haven't tested this code. Still struggling with recursion. Please tell me if it worked or what error it gave.
The previous answer i gave was really bad.
I ran the code in DrScheme and it gave errors.
However I have modified it. Here is a code that works:
(define sorted?
(lambda (l)
(cond ((null? l) #t)
(else (if (check-asc? (car l) (cdr l)) #t
(check-desc? (car l) (cdr l)))))))
(define check-asc?
(lambda (elt lst)
(cond ((null? lst) #t)
(else (if (or (< elt (car lst)) (= elt (car lst))) (check-asc? (car lst) (cdr lst))
#f)))))
(define check-desc?
(lambda (elt lst)
(cond ((null? lst) #t)
(else (if (or (> elt (car lst)) (= elt (car lst))) (check-desc? (car lst) (cdr lst))
#f)))))
Cases checked:
(sorted? '(5 4 3 2 1))
returns #t
(sorted? '(1 2 3 4 5))
returns #t
(sorted? '(1 2 3 5 4))
returns #f
(sorted? '())
returns #t
(sorted? '(1))
returns #t

double in scheme

How to write a program in scheme that takes an arbitrary
sexpression consisting of integers and which returns an sexpression that is identical to
the original but with all the integers doubled?
We want a procedure that takes an S-expression as input, and outputs an S-expression with the same structure, but where each integer is doubled; generally, a procedure to map S-expressions:
(define (double x)
(if (number? x)
(* x 2)
x)))
(define (sexp-map op sexp)
...)
(sexp-map double some-sexpression)
The S-expression we get (SEXP) is going to be either an atom, in which case the result is (OP SEXP), or a list of S-expressions. We might think to map OP across SEXP in this case, but S-expressions nest arbitrarily deep. What we should actually do is map a procedure that will transform each element in the smaller S-expression with OP. Well would you look at that, that's just another way to describe of the goal of the procedure we're currently trying to write. So we can map SEXP-MAP across SEXP.
Well, no we can't actually, because SEXP-MAP needs to be called with two arguments, and MAP will only give it the one. To get around that, we use a helper procedure F of one argument:
(define (sexp-map op sexp)
(define (f x)
(if (list? x)
(map f x)
(op x)))
(f sexp))
F winds up doing all the real work. SEXP-MAP is reduced to being a facade that's easier to use for the programmer.
It sounds like what you want is to find each integer in the s-expression, then double it, while keeping the rest of it the same.
If you're not aware, s-expressions are just lists that may happen to contain other lists, and it makes sense to deal with them in levels. For instance, here's a way to print all the values on level one of an s-expression:
(define (print-level-one sexp)
(display (car sexp))
(print-level-one (cdr sexp)))
This will end up calling display on the car of every part of the s-expression.
You could do something similar. You'll need the functions integer? and pair? to check whether something is an integer, which should be doubled, or another list, which should be treated just like the top-level list.
(Note: I'm being deliberately vague because of the comment about homework above. If you just want the answer, rather than help figuring out the answer, say so and I'll change this.)
An Sexp of numbers is one of
-- Number
-- ListOfSexp
A ListOfSexp is one of
-- empty
-- (cons Sexp ListOfSexp)
So, you'll need one function to handle both of those data definitions. Since the data definitions cross-reference each other, the functions will do the same. Each individual function is pretty straight forward.
(define (double E)
(cond ((null? E) '())
((list? (car E)) (cons (double (car E)) (double (cdr E))))
((number? E) (list E))
(else (cons (* 2 (car E)) (double (cdr E))))
))
(map (lambda (x) (* x 2)) '(1 2 3 4 5)) => '(2 4 6 8 10)
What does it do? (lambda (x) (* x 2)) takes a number and doubles it, and map applies that function to every element of a list.
Edit: Oh, but it won't go into trees.
(define double
(lambda (x)
(cond ((null? x) (list))
((list? (car x)) (cons (double (car x)) (double (cdr x))))
(else (cons (* 2 (car x)) (double (cdr x)))))))
EDIT
Fixed this. Thanks to Nathan Sanders for pointing out my initial oversight concerning nested lists.

Resources