scheme - why does this function take much longer to run - scheme

I have these two functions, foldl and foldr. After a chain of function definitions were made i tested two alternatives, and the only differences i could find between the two chains for function calls and definitions was between these two functions, and for some reason the function that calls foldr takes exceptionally longer (tested with large input)
Here is foldl:
(define (foldl op z ls)
(if (null? ls)
z
(foldl op (op z (car ls)) (cdr ls))))
and here is foldr:
(define (foldr op z ls)
(if (null? ls)
z
(op (car ls) (foldr op z (cdr ls)))))
My question is why does the chain that calls foldr, take a ridiculously longer time to run compared to the chain that calls foldl?

Your implementation of foldl is tail recursive because the foldl is the last function called each time through. Your implementation of foldr is not tail recursive because op is the last thing called each time through.
Ok, so what does that mean?
When foldl calls itself each time through, op has already been applied and returned a value. The compiler can optimize this into an equivalent loop. In contrast, when foldr calls itself, op still needs to be applied and so the program must remember to apply op after the recursive call to foldr returns a value. Unfortunately, the recursive call to foldr cannot return a value until op is applied to the next recursive call to foldr and so on until the end of the list. Then at the end of the list, each of the pending applications of op must be applied one by one.
Remembering all the applications of op that are pending takes time and memory space.

Related

Does a non-null Scheme list contain at least one atom?

In The Little Schemer (4th Ed.) it is claimed that a list for which null? is false contains at least one atom, or so I understand from my reading of the text.
This doesn't make sense to me, since (atom '()) is false, and we can stick those into a list to make it non-null:
> (null? '(()))
#f
So my question is, is this a mistake in my reading, or a matter of definitions? Since it's not in the errata I assume such a well-studied book wouldn't have a mistake like this.
If we considered (()) to be the same as (() . ()) or even (cons '() '()) and then considered cons an atom then I could see how you can get there, but I don't think that's what's going on.
(this was tested in Racket 7.0, with the definition of atom? given in the book, i.e.
(define atom?
(lambda (x)
(and (not (pair? x)) (not (null? x)))))
I know this doesn't cover funny Racket features, but should be sufficient here.)
lat is assumed to be a list of atoms at that point in the book.
If it's not empty, by definition it contains some atoms in it.
It's not about Lisp, it's about the book's presentation.
I think lat indicates list of atoms. Thus if lat is not null?, then it needs to contain at least one atom.
There is a procedure called lat? defined as such:
(define lat?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l))
(lat? (cdr l)))
(else #f))))
(lat? '(()) ; ==> #f so by definition '(()) is not a lat and thus the statement does not apply to that list.
A list can contain any type of elements, including empty and other lists, both which are not atoms. lat is a restricted to a flat list with only atomic elements.
As a concept an “atom” is something that can not be broken into smaller parts. A number 42 is an atom, a list (42 43) is not an atom since it contains two smaller parts (namely the numbers 42 and 43). Since an empty list does not contain any smaller parts, it is by this logic an atom.
Now let’s attempt to implement an atom? predicate, that determines whether it’s input is an atom.
(define (atom? x)
(cond
[(number? x) #t]
[(symbol? x) #t]
[(char? x) #t]
...
[else #f]))
Here the ... needs to be replaced with a test for every atomic data type supported by the implementation. This can potentially be a long list. In order to avoid this, we can try to be clever:
(define (atom? x)
(not (list? x)))
This will correctly return false for non-empty lists, and true for numbers, characters etc. However it will return false for the empty list.
Since it is up to the authors of the book to define the term “atom” (the word does not appear in the language standard) they might have opted for the above simple definition.
Note that the definition as non-list is misleading when the language contains other compound data structures such as vectors and structures. If I recall correctly the only compound data structure discussed in the book is lists.

Is there an elisp function like "cl-every" that returns nil on lists of unequal length?

I want to compare two lists in elisp using (cl-every #'eq list1 list2). However, this can return t if one of the lists is longer than the other, and I don't want that. I could call length on the lists, but then I'm traversing each list twice, which is needlessly inefficient. Is there a function like cl-every that also checks for equal lengths as well?
OOTB
I don't think there is such a function OOTB.
Roll your own
I don't think it is hard to implement one, just modify cl-every.
Length
Note that length is implemented in C and, unless your lists are huge, should not noticeably affect performance:
(defun list-elements-eq (l1 l2)
(and (= (length l1)
(length l2))
(every #'eq l1 l2)))
Equal
You can also use equal for your lists: since equal starts with testing for eq, it will be a weaker relationship than what you want.
Beware that in Common Lisp equal may not terminate for circular structures.
Emacs Lisp is "smarter": it detects cicularity:
(setq x (list 1))
(setcdr x x)
(setq y (list 1))
(setcdr y y)
(eq x y)
(equal x y)
Debugger entered--Lisp error: (circular-list #1=(1 . #1#))
equal(#1=(1 . #1#) #2=(1 . #2#))
(arguably, it should returns t instead).
Common Lisp
Generally speaking, Common Lisp is a better language for "heavy lifting".
If your lists are huge, you might want to use it instead of Emacs Lisp:
(defun list-elements-eq (l1 l2)
(if (endp l1)
(endp l2)
(and (not (endp l2))
(eq (pop l1) (pop l2))
(list-elements-eq l1 l2))))
This is tail-recursive, and any decent CL will optimize recursion away (possibly depending on the optimize setting).
You don't want to use deep recursion in ELisp (see Why is there no tail recursion optimization in Emacs lisp, not but like other scheme?).

DrRacket - Intermediate Student With Lambda - List ordering

I have an assignment question that asks me to write a function, using lambda, that consumes a list of numbers and removes all but the first occurrence of each number. My function is I think quite nice, with the exception that it produces the wrong result! It produces a list that contains the last occurrence of each number. It produces a list with the same values as the proper list, just in different order. Here's my code:
(define (remove-duplicates numlist)
(foldr (lambda (a b)
(cond
[(not (member? a b)) (cons a b)]
[else b])) empty numlist))
I've tried using foldl instead of foldr but, not surprisingly, it produces the correct list, but in reverse. Is there a way of producing the correct list without resorting to reversing the list created by foldl with another lambda expression?
Please keep in mind, this is homework so no explicit answers please.
Thanks everyone!
Think about how foldr behaves, semantically. It starts at the rightmost element of the list, and performs the fold, moving leftwards. That means that in your lambda function, a represents the element directly to the left of the thus-far-folded list, and b represents the result of folding everything to the right of the list element a. With this in mind, consider:
[(not (member? a b)) (cons a b)]
[else b]
You check whether the list b already contains a. If it does, then you discard a, keeping b as it is. This explains why your code keeps the last (rightmost) occurrence, and not the first. If you wish to perform a right fold, then, you must change your logic. You need to somehow "purge" b of the offending element a that it contains.
[(not (member? a b)) (cons a b)]
[else (cons a (purge a b))]
This way, you will eventually keep only the leftmost, rather than the rightmost, occurrence of each unique element. It may be wise to perform member? and purge simultaneously, since they both must traverse the list; this would require additional refactoring.
Note that, since the function takes O(n2) time anyways, it really doesn't hurt the time complexity to add a O(n) reverse to the foldl version.

Implementing a "Pythonic" map in Scheme: bad idea?

In Scheme, the function (map fn list0 [list1 .. listN]) comes with the restriction that the lists must have the same number of elements. Coming from Python, I'm missing the freedom of Python list comprehensions, which look a lot like map above, but without this restriction.
I'm tempted to implement an alternative "my-map", which allows for lists of differing size, iterating through the first N elements of all lists, where N is the length of the shortest list.
For example, let num be 10 and lst be (1 2 3). With my-map, I hope to write expressions like:
(my-map + (circular-list num) lst)))
And get:
(11 12 13)
I have an easier time reading this than the more conventional
(map + (lambda (arg) (+ num arg)) lst)
or
(map + (make-list (length lst) num) lst)
Two questions:
As a Scheme newbie, am I overlooked important reasons for the restriction on `map`?
Does something like `my-map` already exist in Scheme or in the SRFIs? I did take a look at srfi-42, but either it's not what I'm looking for, or it was, and it wasn't obvious.
First, note that map does allow empty lists, but of course if there's one empty list then all of them should be empty.
Second, have a look at the srfi-1 version of map -- it is specifically different from the R5RS version as follows:
This procedure is extended from its R5RS specification to allow the arguments to be of unequal length; it terminates when the shortest list runs out.
Third, most Scheme programmers would very much prefer
(map (lambda (arg) (+ num arg)) lst)
My guess is that Scheme is different from Python in a way that makes lambda expressions become more and more readable as you get used to the language.
And finally, there are some implementations that come with some form of a list comprehension. For example, in Racket you can write:
(for/list ([arg lst]) (+ num arg))

How to declare a variable inside a Scheme function?

Is it possible to do so? Let's say I want to get the last element of a list, I would create a variable i = 0, and increment it until it equals to length. Any idea? An example would be greatly appreciated.
Thanks,
There are several ways to declare a variable; the cleanest one is let:
(let ((x some-expr))
; code block that uses x
But you don't need this to get the last element of a list. Just use recursion:
(define (last xs)
(if (null? (cdr xs))
(car xs)
(last (cdr xs))))
Note: if you want, you can use a variable to cache cdr's result:
(define (last xs)
(let ((tail (cdr xs)))
(if (null? tail)
(car xs)
(last tail))))
Yes, it's possible to define local variables in scheme, either using let or define inside a function. Using set!, it's also possible to reassign a variable like you imagine.
That being said, you should probably not solve your problem this way. In Scheme it's generally good practice to avoid set! when you don't need to (and in this case you definitely don't need to). Further iterating over a list using indices is usually a bad idea as scheme's lists are linked lists and as such random access O(n) (making the last function as you want to implement it O(n^2)).
So a simple recursive implementation without indices would be more idiomatic and faster than what you're planning to do and as such preferable.

Resources