Efficiency issue on Guile SCHEME: member and equal? - performance

I am new on SCHEME programming and after some while I succeeded on writing a couple of scripts to deal with long maths formulas.
The issue is that its execution is pretty slow. After profiling I realized that the execution takes about 35% of the time executing the built-in functions equal? and member.
My question is regarding whether there exist more efficient version of those functions or I should re-factor the code in order to remove its calls?
I'm about to re-write the code so I would really appreciate any piece of advice.
Thanks!
EDIT 1:
I add some code for making the question clearer. The following function takes two parameters, a pair (x,y) and a term, x and y are usually variable names(symbols), but they may be a symbol and a number, a list and a symbol, etc. The term is a list such as
(+ w y z (* (- 1) x))
so after the function execution I would get something like
(+ w z)
The code looks like the following:
(define (simp-by-term_eq t_CC t)
(cond
((and (member (list '* (list '- 1) (car t_CC)) (cdr t))
(member (cadr t_CC) (cdr t)))
(delete-1st (cadr t_CC)
(delete-1st (list '* (list '- 1) (car t_CC)) (cdr t)))
)
((and (member (list '* (car t_CC) (list '- 1)) (cdr t))
(member (cadr t_CC) (cdr t)))
(delete-1st (cadr t_CC)
(delete-1st (list '* (car t_CC) (list '- 1)) (cdr t)))
)
(else t)
)
)
There are several conditions like the previous one on the function.
The equal function calls are mainly used into filter callse such as
(filter (lambda (x) (and (not (equal? (list '* (car t_CC) (list '- 1)) x))
(not (equal? (list '* (list '- 1) (car t_CC)) x)))) t)

equal? needs to test every part of list structure so basically it traverses both operands until it has touched all sequences and compared all atomic values. If you need to test if it's the same you can use eq? which only checks that the pair has the same address. Thus it will evaluate to #f even when the list structure look the same. Sometimes that's ok. eqv? is similar to eq? but it also works for numbers and characters (but not strings).
You can use memq that uses eq? instead of equal? and you can use memqv that uses eqv? which also works for numbers and characters.
I'm not that familiar with Guile but if you have performance issues and are using member perhaps you should consider hash tables instead?
It could happen you need to rethink the algorithm you use too if you really need to use equal?, but without specific code it's difficult to be more specific.

Related

Getting the ordered leaves of a tree in scheme

I'm going through an exercise to grab the 'leaves' of a nested list in scheme (from SICP). Here is the exercise input-output:
(define x (list (lis 1 2) (list 3 4)))
(fringe x)
; (1 2 3 4)
(fringe (list x x))
; (1 2 3 4 1 2 3 4)
Now, I've come up with two answers for this: one recursive and one iterative. Here are my two implementations below:
(define (fr lst)
(cond ((null? lst) '())
((not (pair? (car lst))) (cons (car lst) (fr (cdr lst))))
(else (append (fr (car lst)) (fr (cdr lst))))))
(define (add-element-to-list lst elem)
(if (null? lst)
(list elem)
(cons (car lst) (add-element-to-list (cdr lst) elem))))
(define (fringe lst)
(define L '())
(define (iter lst)
(if (not (pair? (car lst)))
(set! L (add-element-to-list L (car lst))) ; update the list if it's a leaf
(iter (car lst))) ; otherwise recurse
(if (not (null? (cdr lst))) (iter (cdr lst))) ; and if we have a cdr, recurse on that
L
)
(iter lst)
)
(fringe x)
(fr x)
(fr (list x x))
(fringe (list x x))
; (1 2 3 4)
; (1 2 3 4)
; (1 2 3 4 1 2 3 4)
; (1 2 3 4 1 2 3 4)
; OK
The problem for me is, this exercise took me forever to figure out with a ton of head-bashing along the way (and it's still difficult for me to 'get it' as I write this up). Here are a few things I struggled with and seeing if there are any suggestions on ways to deal with these issues in scheme:
I thought initially that there are two cases. The normal/scalar case and the nested case. However, it seems like there are actually three! There's the normal case, the nested case, and then the null case -- and inner-lists also have the null case! Is there a good general pattern or something to account for the null case? Is this something that comes up a lot?
In the iterative case, why do I have to return L at the end? Why doesn't (iter lst) just return that (i.e., if I removed the standalone-L at the bottom of the iter function).
Finally, is there a 'cleaner' way to implement the iterative case? It seems like I have so much code, where it could probably be improved on.
The reason there are three cases is that you are importing some scalar / vector distinction from some other language: Scheme doesn't have it and it is not helpful. Instead a list is a recursively-defined object: a list is either the empty list, or it is a pair of something and a list. That means there are two distinctions to make, not one: is an object a pair, and is an object the empty list:
(define (lyst? o)
(or (null? o)
(and (pair? o) (lyst? (cdr o)))))
That's completely different than a vector / scalar distinction. I don't know what language you're getting this from, but just think about how the maths of this would work: vectors are defined over some scalar field, and there is no vector which is also a scalar. But for lists there is a list which is not a pair. Just stop thinking about vectors and scalars: it is not a helpful way to think about lists, pairs and the empty list.
The iterative version is too horrible to think about: there's a reason why SICP hasn't introduced set! yet.
First of all it's not actually iterative: like most of the 'iterative' solutions to this problem on the net it looks as if it is, but it's not. The reason it's not is that the skeleton of the iter function looks like
if blah
recurse on the first element of the list
otherwise do something else
if other blah
iterate on the rest of the list
And the critical thing is that both (1) and (2) always happen, so the call into the car of the list is not a tail call: it's a fully-fledged recursive call.
That being said you can make this much better: the absolutely standard way of doing this sort of thing is to use an accumulator:
(define (fringe l)
(define (fringe-loop thing accum)
(cond
((null? thing)
;; we're at the end of the list or an element which is empty list
accum)
((pair? thing)
;; we need to look at both the first of the list and the rest of the list
;; Note that the order is rest then first which means the accumulator
;; comes back in a good order
(fringe-loop (car thing)
(fringe-loop (cdr thing) accum)))
(else
;; not a list at all: collect this "atomic" thing
(cons thing accum))))
(fringe-loop l '()))
Note that this builds the fringe (linear) list from the bottom up, which is the natural way of building linear lists with recursion. To achieve this it slightly deviously orders the way it looks at things so the results come out in the right order. Note also that this is also not iterative: it's recursive, because of the (fringe-loop ... (fringe-loop ...)) call. But this time that's much clearer.
The reason it's not iterative is that the process of searching a (tree-like, Lisp) list is not iterative: it's what SICP would call a 'recursive process' because (Lisp's tree-like) lists are recursively defined in both their first and rest field. Nothing you can do will make the process iterative.
But you can make the code to appear iterative at the implementation level by managing the stack explicitly thus turning it into a tail recursive version. The nature of the computational process doesn't change though:
(define (fringe l)
(define (fringe-loop thing accum stack)
(cond
((null? thing)
;; ignore the () sentinel or () element
(if (null? stack)
;; nothing more to do
accum
;; continue with the thing most recently put aside
(fringe-loop (car stack) accum (cdr stack))))
((pair? thing)
;; carry on to the right, remembering to look to the left later
(fringe-loop (cdr thing) accum (cons (car thing) stack)))
(else
;; we're going to collect this atomic thing but we also need
;; to check the stack
(if (null? stack)
;; we're done
(cons thing accum)
;; collect this and continue with what was put aside
(fringe-loop (car stack) (cons thing accum) (cdr stack))))))
(fringe-loop l '() '()))
Whether that's worth it depends on how expensive you think recursive calls are and whether there is any recursion limit. However the general trick of explicitly managing what you are going to do next is useful in general as it can make it much easier to control search order.
(Note, of course, that you can do a trick like this for any program at all!)
It's about types. Principled development follows types. Then it becomes easy.
Lisp is an untyped language. It's like assembler on steroids. There are no types, no constraints on what you're able to code.
There are no types enforced by the language, but still there are types, conceptually. We code to types, we handle types, we produce values to a given specs i.e. values of some types as needed for the pieces of bigger system to interface properly, for the functions we write to work together properly, etc. etc.
What is it we're building a fringe of? Is it a "list"?
What is a "list"? Is it
(define (list? ls)
(or (null? ls)
(and (pair? ls)
(list? (cdr ls)))))
Is this what we're building a fringe of? How come it says nothing about the car of the thing, are we to ignore anything that's in the car? Why, no, of course not. We're not transforming a list. We're actually transforming a tree:
(define (tree? ls)
(or (null? ls)
(and (pair? ls)
(tree? (car ls))
(tree? (cdr ls)))))
Is it really enough though to only be able to have ()s in it? Probably not.
Is it
(define (tree? ls)
(or (null? ls)
(not (pair? ls)) ;; (atom? ls) is what we mean
(and ;; (pair? ls)
(tree? (car ls))
(tree? (cdr ls)))))
It 1 a tree? Apparently it is, but let's put this aside for now.
What we have here, is a structured, principled way to see a piece of data as belonging to a certain type. Or as some say, data type.
So then we just follow the same skeleton of the data type definition / predicate, to write a function that is to process the values of said type in some specific way (this is the approach promoted by Sterling and Shapiro's "The Art of Prolog").
(define (tree-fringe ls)
So, what is it to produce? A list of atoms in its leaves, that's what.
(cond
((null? ls)
A () is already a list?.
ls)
((not (pair? ls)) ;; (atom? ls) is what we mean
(handle-atom-case ls))
Let's put this off for now. On to the next case,
(else
;; (tree? (car ls))
;; (tree? (cdr ls))
both car and cdr of ls are tree?s. How to handle them, we already know. It's
(let ((a (tree-fringe (car ls)))
(b (tree-fringe (cdr ls)))
and what do we do with the two pieces? We piece them together. First goes the fringe from the left, then from the right. Simple:
(append a b )))))
(define (handle-atom-case ls)
;; bad name, inline its code inside
;; the `tree-fringe` later, when we have it
And so, what type of data does append expect in both its arguments? A list?, again.
And this is what we must produce for an atomic "tree". Such "tree" is its own fringe. Except,
;; tree: 1 2
;; fringe: ( 1 ) ( 2 )
it must be a list?. It's actually quite simple to turn an atomic piece of data, any data, into a list? containing that piece of data.
........ )
And that was the only non-trivial thing we had to come up with here, to get to the solution.
Recursion is about breaking stuff apart into the sub-parts which are similar to the whole thing, transforming those with that same procedure we are trying to write, then combining the results in some simple and straightforward way.
If a tree? contains two smaller trees?, well, we've hit the jackpot -- we already know how to handle them!
And when we have structural data types, we already have the way to pick them apart. It is how they are defined anyway.
Maybe I'll address your second question later.

Maximum recursion error [duplicate]

I'm reading The Little Schemer. And thanks to my broken English, I was confused by this paragraph:
(cond ... ) also has the property of not considering all of its
arguments. Because of this property, however, neither (and ... ) nor
(or ... ) can be defined as functions in terms of (cond ... ), though
both (and ... ) and (or ... ) can be expressed as abbreviations of
(cond ... )-expressions:
(and a b) = (cond (a b) (else #f)
and
(or a b) = (cond (a #t) (else (b))
If I understand it correctly, it says (and ...) and (or ...) can be replaced by a (cond ...) expression, but cannot be defined as a function that contains (cond ...). Why is it so? Does it have anything to do with the variant arguments? Thanks.
p.s. I did some searching but only found that (cond ...) ignores the expressions when one of its conditions evaluate to #f.
Imagine you wrote if as a function/procedure rather than a user defined macro/syntax:
;; makes if in terms of cond
(define (my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))
;; example that works
(define (atom? x)
(my-if (not (pair? x))
#t
#f))
;; example that won't work
;; peano arithemtic
(define (add a b)
(my-if (zero? a)
b
(add (- a 1) (+ b 1))))
The problem with my-if is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom? the parts (not (pair? x)), #t and #f were evaluated before the body of my-if gets executed.
For the last example means (add (- a 1) (+ b 1)) gets evaluated regardless of what a is, even when a is zero, so the procedure will never end.
You can make your own if with syntax:
(define-syntax my-if
(syntax-rules ()
((my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))))
Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It's replaced with the other just reusing the expressions so that:
(my-if (check-something) (display 10) (display 20))
would be replaced with this:
(cond ((check-something) (display 10))
(else (display 20)))
With the procedure version of my-if both 10 and 20 would have been printed. This is how and and or is implemented as well.
You cannot define cond or and or or or if as functions because functions evaluate all their arguments. (You could define some of them as macros).
Read also the famous SICP and Lisp In Small Pieces (original in French).

How to implement call-with-values to match the values example in R5RS

R5RS says...
Values might be defined as follows:
(define (values . things)
(call-with-current-continuation
(lambda (cont) (apply cont things))))
It doesn’t, however, say how call-with-values might be implemented if values were implemented this way. So, if values is implemented this way, how would call-with-values be implemented?
(This came up because I was trying to get some code that used call-with-values to work with TinyScheme, which doesn’t support it. I managed by faking values and call-with-values with lists, but—when I saw this in R5RS—I wanted to know if this might be a better workaround.)
Kent Dybvig defines call/cc, values and call-with-values thusly:
(define call/cc call/cc)
(define values #f)
(define call-with-values #f)
(let ((magic (cons 'multiple 'values)))
(define magic?
(lambda (x)
(and (pair? x) (eq? (car x) magic))))
(set! call/cc
(let ((primitive-call/cc call/cc))
(lambda (p)
(primitive-call/cc
(lambda (k)
(p (lambda args
(k (apply values args)))))))))
(set! values
(lambda args
(if (and (not (null? args)) (null? (cdr args)))
(car args)
(cons magic args))))
(set! call-with-values
(lambda (producer consumer)
(let ((x (producer)))
(if (magic? x)
(apply consumer (cdr x))
(consumer x))))))
The short answer is: You can't
The nifty implementation of values does not change the fact that there is no way to implement the other procedures if you don't have any of them to poke at the values. If you had one way to peek then you could implement the others with that.
(+ (values 4 5))
(apply + (values 4 5))
Doesn't work and that's why you need those other primitives.
When that said. There is no difference between returning more values and returning lists with values since the difference is optimization. You could make a macro that treats both of them as a binding and then the way you use them would be the same. The difference in performance is some pointer jumping and some consing which is reasonable fast for any lisp implementation. Heres a minimalistic implementation that will work given your code is correct:
(define values list)
(define (call-with-values producer consumer)
(apply consumer (producer)))

How Do For Loops Work In Scheme?

I'm having some difficulty understanding how for loops work in scheme. In particular this code runs but I don't know why
(define (bubblesort alist)
;; this is straightforward
(define (swap-pass alist)
(if (eq? (length alist) 1)
alist
(let ((fst (car alist)) (scnd (cadr alist)) (rest (cddr alist)))
(if (> fst scnd)
(cons scnd (swap-pass (cons fst rest)))
(cons fst (swap-pass (cons scnd rest)))))))
; this is mysterious--what does the 'for' in the next line do?
(let for ((times (length alist))
(val alist))
(if (> times 1)
(for (- times 1) (swap-pass val))
(swap-pass val))))
I can't figure out what the (let for (( is supposed to do here, and the for expression in the second to last line is also a bit off putting--I've had the interpreter complain that for only takes a single argument, but here it appears to take two.
Any thoughts on what's going on here?
That's not a for loop, that's a named let. What it does is create a function called for, then call that; the "looping" behavior is caused by recursion in the function. Calling the function loop is more idiomatic, btw. E.g.
(let loop ((times 10))
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))
gets expanded to something like
(letrec ((loop (lambda (times)
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))))
(loop 10))
This isn't actually using a for language feature but just using a variation of let that allows you to easily write recursive functions. See this documentation on let (it's the second form on there).
What's going on is that this let form binds the name it's passed (in this case for) to a procedure with the given argument list (times and val) and calls it with the initial values. Uses of the bound name in the body are recursive calls.
Bottom line: the for isn't significant here. It's just a name. You could rename it to foo and it would still work. Racket does have actual for loops that you can read about here.

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