I'm writing a program that directs a robot down a BST to the goal number. The program has two input parameters, a destination as an integer, and a map that represents all the paths the robot can follow.
ie: (robot 64 '(53 ( () ( 64 () () ) ))) )
Where 64 is the destination and 53 ( () ( 64 () () ) )) is the BST.
I need help writing the method. Here is what I was originally working on.
(define (robot goal map)
(let ((x (car map)))
(define empty? '())
(display x)
(cond (empty? x)
(robot goal (cadr map)))
(cond ((= goal x)) (display x))
(cond (< x goal)
(robot goal (cadr map)))
(cond (> x goal)
(robot goal (caddr map)))
;(display "NULL")
)
)
It's supposed to search through the BST, and if the path is found it prints (found: # T # T ... # T #), if your destination is in the tree but not the root (# is a position number and T is either L or R indicating that you took a Left or Right turn at position #.
Note: I've never used Lisp until yesterday, so sorry if I seem a bit lost.
The procedure's structure is incorrect for the problem at hand - you're not handling the recursion correctly, and you're not building a list along the way, for the requested output. Also that's not the correct way to use cond, and you should not redefine the existing procedures map and empty?. Also, what happens if the element is not in the tree? you can't do (car tree) until you're certain that the tree is non-empty.
I'll provide the correct structure of the solution and give you some hint so you can work out the solution by yourself, if the element was not found in the tree we'll return a list with the value not-found in the last position.
(define (robot goal tree)
(cond ((empty? tree) ; if the tree is empty
'(not-found)) ; return special value indicating it
((= <???> goal) ; if the current element is goal
<???>) ; return a list with current element
((< goal <???>) ; if goal is less than current element
(cons <???> ; cons current element
(cons <???> ; with L and advance the recursion
(robot goal <???>)))) ; going to the left
(else ; otherwise
(cons <???> ; cons current element
(cons <???> ; with R and advance the recursion
(robot goal <???>)))))) ; going to the right
Notice that the correct way to search a BST will always be:
Check if the tree is empty
If not, check if the current element is the one we're looking for
If not, check if the element we're looking for is less than the current element, and go to the left subtree if that's the case
Otherwise go to the right subtree
As a final advice, don't forget to test your solution:
(robot 64 '(53 () (64 () ())))
=> '(53 R 64)
(robot 42 '(53 () (64 () ())))
=> '(53 L not-found)
Related
I am working on problem to get the occurence of Prime in a list in lisp.
Input:
Write a function (OccurencesOfPrimes < list >) which counts the number of primes in a (possibly nested) list.
Output: Example: (OccurencesOfPrimes (((1)(2))(5)(3)((8)3)) returns 4.
I am using the below code but getting the error like:
(
defun OccurencesOfPrimes (list)
(loop for i from 2 to 100
do ( setq isPrime t)
(loop for j from 2 to i
never (zerop (mod i j))
(setq isPrime f)
(break)
)
)
(if (setq isPrime t)
(append list i)
)
)
)
LOOP: illegal syntax near (SETQ ISPRIME F) in
(LOOP FOR J FROM 2 TO I NEVER (ZEROP (MOD I J)) (SETQ ISPRIME F) (BREAK)
)
Any help.
It is important to keep the format consistent with the expected conventions of the language. It helps when reading the code (in particular with other programmers), and can help you see errors.
Also, you should use an editor which, at the minimum, keep tracks of parentheses. In Emacs, when you put the cursor in the first opening parenthesis, the matching parenthesis is highlighted. You can spot that you have one additional parenthesis that serves no purpose.
(
defun OccurencesOfPrimes (list)
(loop for i from 2 to 100
do ( setq isPrime t)
(loop for j from 2 to i
never (zerop (mod i j))
(setq isPrime f)
(break)
)
)
(if (setq isPrime t)
(append list i)
)
) ;; <- end of defun
) ;; <- closes nothing
In Lisp, parentheses are for the computer, whereas indentation is for humans. Tools can automatically indent the code according to the structure (the parenthesis), and any discrepancy between what indentation you expect and the one being computed is a hint that your code is badly formed. If you look at the indentation of your expressions, you can see how deep you are in the form, and that alone helps you understand the code.
Symbol names are dash-separated, not camlCased.
Your code, with remarks:
(defun occurences-of-primes (list)
;; You argument is likely to be a LIST, given its name and the way
;; you call APPEND below. But you never iterate over the list. This
;; is suspicious.
(loop
for i from 2 to 100
do
(setq is-prime t) ;; setting an undeclared variable
(loop
for j from 2 to i
never (zerop (mod i j))
;; the following two forms are not expected here according
;; to LOOP's grammar; setting IS-PRIME to F, but F is not
;; an existing variable. If you want to set to false, use
;; NIL instead.
(setq is-prime f)
;; BREAK enters the debugger, maybe you wanted to use
;; LOOP-FINISH instead, but the NEVER clause above should
;; already be enough to exit the loop as soon as its
;; sub-expression evaluates to NIL.
(break)))
;; The return value of (SETQ X V) is V, so here your test would
;; always succeed.
(if (setq is-prime t)
;; Append RETURNS a new list, without modifying its
;; arguments. In particular, LIST is not modified. Note that "I"
;; is unknown at this point, because the bindings effective
;; inside the LOOP are not visible in this scope. Besides, "I"
;; is a number, not a list.
(append list i)))
Original question
Write one function which counts all the occurrences of a prime number in a (possibly nested) list.
Even though the homework questions says "write one function", it does not say that you should write one big function that compute everything at once. You could write one such big function, but if you split your problem into sub-problems, you will end with different auxiliary functions, which:
are simpler to understand (they do one thing)
can be reused to build other functions
The sub-problems are, for example: how to determine if a number is a prime? how to iterate over a tree (a.k.a. a possibly nested list)? how to count
the occurrences?
The basic idea is to write an "is-prime" function, iterate over the tree and call "is-prime" on each element; if the element is prime and was never seen before, add 1 to a counter, local to your function.
You can also flatten the input tree, to obtain a list, then sort the resulting
list; you iterate over the list while keeping track of the last
value seen: if the value is the same as the previous one, you
already know if the number is prime; if the previous number differs, then
you have to test if the number is prime first.
You could also abstract things a little more, and define a higher-order tree-walker function, which calls a function on each leaf of the tree. And write another higher-order function which "memoizes" calls: it wraps around a
function F so that if you call F with the same arguments as before,
it returns the result that was stored instead of recomputing it.
Example
I'll combine the above ideas because if you give that answer to a teacher you are likely to have to carefully explain what each part does (and if you can, great for you); this is not necessarily the "best" answer, but it covers a lot of things.
(defun tree-walk-leaves (tree function)
(typecase tree
(null nil)
(cons
(tree-walk-leaves (car tree) function)
(tree-walk-leaves (cdr tree) function))
(t (funcall function tree))))
(defun flatten (tree &optional keep-order-p)
(let ((flat nil))
(tree-walk-leaves tree (lambda (leaf) (push leaf flat)))
(if keep-order-p
(nreverse flat)
flat)))
(defun prime-p (n)
(or (= n 2)
(and (> n 2)
(oddp n)
(loop
for d from 3 upto (isqrt n) by 2
never (zerop (mod n d))))))
(defun count-occurences-of-prime (tree)
(count-if #'prime-p (remove-duplicates (flatten tree))))
(count-occurences-of-prime '(((1)(2))(5)(3)((8)3)))
=> 4
If, instead, you don't want to remove duplicates but count the multiple times a prime number occurs, you can do:
(count-if (memoize #'prime-p) (flatten tree))
... where memoize is:
(defun memoize (function &key (test #'equalp) (key #'identity))
(let ((hash (make-hash-table :test test)))
(lambda (&rest args)
(let ((args (funcall key args)))
(multiple-value-bind (result exists-p) (gethash args hash)
(values-list
(if exists-p
result
(setf (gethash args hash)
(multiple-value-list (apply function args))))))))))
(memoize is useless if there are no duplicates)
I have the following setup in Common Lisp. my-object is a list of 5 binary trees.
(defun make-my-object ()
(loop for i from 0 to 5
for nde = (init-tree)
collect nde))
Each binary tree is a list of size 3 with a node, a left child and a right child
(defstruct node
(min 0)
(max 0)
(ctr 0))
(defun vals (tree)
(car tree))
(defun left-branch (tree)
(cadr tree))
(defun right-branch (tree)
(caddr tree))
(defun make-tree (vals left right)
(list vals left right))
(defun init-tree (&key (min 0) (max 1))
(let ((n (make-node :min min :max max)))
(make-tree n '() '())))
Now, I was trying to add an element to one of the binary trees manually, like this:
(defparameter my-object (make-my-object))
(print (left-branch (car my-object))) ;; returns NIL
(let ((x (left-branch (car my-object))))
(setf x (cons (init-tree) x)))
(print (left-branch (car my-object))) ;; still returns NIL
The second call to print still returns NIL. Why is this? How can I add an element to the binary tree?
The first function is just:
(defun make-my-object ()
(loop repeat 5 collect (init-tree)))
Now you define a structure for node, but you use a list for the tree and my-object? Why aren't they structures?
Instead of car, cadr and caddr one would use first, second, third.
(let ((x (left-branch (car my-object))))
(setf x (cons (init-tree) x)))
You set the local variable x to a new value. Why? After the let the local variable is also gone. Why aren't you setting the left branch instead? You would need to define a way to do so. Remember: Lisp functions return values, not memory locations you can later set. How can you change the contents in a list? Even better: use structures and change the slot value. The structure (or even CLOS classes) has following advantages over plain lists: objects carry a type, slots are named, accessors are created, a make function is created, a type predicate is created, ...
Anyway, I would define structures or CLOS classes for node, tree and object...
Most of the code in this question isn't essential to the real problem here. The real problem comes in with the misunderstanding of this code:
(let ((x (left-branch (car my-object))))
(setf x (cons (init-tree) x)))
We can see the same kind of behavior without user-defined structures of any kind:
(let ((cell (cons 1 2)))
(print cell) ; prints (1 . 2)
(let ((x (car cell)))
(setf x 3)
(print cell))) ; prints (1 . 2)
If you understand why both print statements produce (1 . 2), then you've got enough to understand why your own code isn't doing what you (previously) expected it to do.
There are two variables in play here: cell and x. There are three values that we're concerned with 1, 2, and the cons-cell produced by the call (cons 1 2). Variables in Lisp are often called bindings; the variable, or name, is bound to a value. The variable cell is bound to the the cons cell (1 . 2). When we go into the inner let, we evaluate (car cell) to produce the value 1, which is then bound to the variable x. Then, we assign a new value, 3, to the variable x. That doesn't modify the cons cell that contains the value that x was originally bound to. Indeed, the value that was originally bound to x was produced by (car cell), and once the call to (car cell) returned, the only value that mattered was 1.
If you have some experience in other programming languages, this is directly analogous to something like
int[] array = ...;
int x = array[2]; // read from the array; assign result to x
x = 42; // doesn't modify the array
If you want to modify a structure, you need to setf the appropriate part of the structure. E.g.:
(let ((cell (cons 1 2)))
(print cell) ; prints (1 . 2)
(setf (car cell) 3)
(print cell)) ; prints (3 . 2)
Im really having problems understanding how I can create variable that would act as an accumulator in racket. This is definitely a really stupid question....but racket's documentation is pretty difficult for me to read.
I know I will use some kind of define statement or let statement.
I want to be able to pass a number to a variable or function and it adds the current value with the new value keeps the sum...How would I do this....?? Thank you..
(define (accumulator newvalue) "current=current+newvalue"
something like this..
An accumulator is generally just a function parameter. There are a few chapters in How to Design Programs (online, starting here) that cover accumulators. Have you read them?
For example, the reverse function is implemented using an accumulator that remembers the prefix of the list, reversed:
;; reverse : list -> list
(define (reverse elems0)
;; reverse/accum : list list -> list
(define (reverse/accum elems reversed-prefix)
(cond [(null? elems)
reversed-prefix]
[else
(reverse/accum (cdr elems)
(cons (car elems) reversed-prefix))]))
(reverse/accum elems null))
Note that the scope of the accumulator reversed-prefix is limited to the function. It is updated by calling the function with a new value for that parameter. Different calls to reverse have different accumulators, and reverse remembers nothing from one call to the next.
Perhaps you mean state variable instead. In that case, you define it (or bind it with let or lambda) at the appropriate scope and update it using set!. Here's a global state variable:
;; total : number
(define total 0)
;; add-to-total! : number -> number
(define (add-to-total! n)
(set! total (+ total n))
total)
(add-to-total! 5) ;; => 5
(add-to-total! 31) ;; => 36
Here's a variation that creates local state variables, so you can have multiple counters:
;; make-counter : -> number -> number
(define (make-counter)
(let ([total 0])
(lambda (n)
(set! total (+ total n))
total)))
(define counterA (make-counter))
(define counterB (make-counter))
(counterA 5) ;; => 5
(counterB 10) ;; => 10
(counterA 15) ;; => 20
(counterB 20) ;; => 30
But don't call state variables accumulators; it will confuse people.
Do you mean something like this?
(define (accumulator current newvalue)
(let ((current (+ current newvalue)))
...)
You can close over the accumulator variable:
(define accumulate
(let ((acc 0))
(λ (new-val)
(set! acc (+ acc new-val))
acc)))
(accumulate 10) ;=> 10
(accumulate 4) ;=> 14
It seems that I have to make it in detail; it's my homework. I don't
want to copy the code written by you. I'm a newbie; what I'm trying
to learn is how to decompose a subject to single pieces, and then
focus on what function should I use to solve the problem. It's a
little hard to finish these problems by my own, because I'm completely
a newbie in Lisp, actually in how to program. I hope you can help me
out.
Here is the problem: there is a given constant
(defconstant *storms* '((bob 65)
(chary 150)
(jenny 145)
(ivan 165)
(james 120)))
Each storm is represented by a list of its name and its wind speed.
The wind speeds are to be categorized as follows:
39–74 → tropical
75–95 → cat-1
96–110 → cat-2
111–130 → cat-3
131–155 → cat-4
156 or more → cat-5
Now I have to write two functions:
storm-categories should generate category names, like this: (bob
tropical), (chary cat-1), …
and storm-distribution should generate the number of storms in
each category, like this: (cat-1 1), (cat-2 0), …
The way I try to solve this problem is:
Use if statements to judge the type of windspeed:
(if (and (> x 39) (< x 73)) (print 'tropical))
(if (and (> x 74) (< x 95)) (print 'cat-1))
(if (and (> x 96) (< x 110)) (print 'cat-2))
(if (and (> x 111) (< x 130)) (print'cat-3))
(if (and (> x 131) (< x 155)) (print'cat-4))
(if (and (> x 156)) (print 'cat-5))
Replace the windspeed (like 65) with windtype (like cat-1)
(loop for x in storms
do (rplacd x ‘windtype)
I just have a simple idea of the first function, but still don't know
how to implement it. I haven't touched the distribution function,
because I am still stuck on the first one.
DEFCONSTANT is wrong. It makes no sense to make your input a constant. A variable defined with DEFVAR or DEFPARAMETER is fine.
Instead of IF use COND. COND allows the testing of several conditions.
You don't want to use PRINT. Why print something. You want to compute a value.
RPLACA is also wrong. That's used for destructive modification. You don't want that. You want to create a new value. Something like RPLACA might be used in the function DISTRIBUTION (see below).
Use functional abstraction. Which functions are useful?
BETWEEN-P, is a value X between a and b ?
STORM-CATEGORY, for a given wind speed return the category
STORM-CATEGORIES, for a list of items (storm wind-speed) return a list of items (storm category). Map over the input list to create the result list.
DISTRIBUTION, for a list of items (tag category) return a list with items (category number-of-tags-in-this-category).
STORM-DISTRIBUTION, for a list of items (storm category) return a list with items (category number-of-storms-in-this-category). This basically calls DISTRIBUTION with the right parameters.
The function DISTRIBUTION is the most complicated of the above. Typically one would use a hashtable or a assoc list as an intermediate help to keep a count of the occurrences. Map over the input list and update the corresponding count.
Also: a good introduction into basic Lisp is the book Common Lisp: A Gentle Introduction to Symbolic Computation - it is freely available as a PDF for download. A more fun and also basic introduction to Lisp is the book Land of Lisp.
Okay roccia, you have posted your answer. Here comes mine hacked in a few minutes, but it should give you some ideas:
First let's start with the data:
(defparameter *storms2004*
'((BONNIE 65)
(CHARLEY 150)
(FRANCES 145)
(IVAN 165)
(JEANNE 120)))
(defparameter *storm-categories*
'((39 73 tropical-storm)
(74 95 hurricane-cat-1)
(96 110 hurricane-cat-2)
(111 130 hurricane-cat-3)
(131 155 hurricane-cat-4)
(156 nil hurricane-cat-5)))
A function that checks if a value is between two bounds. If the right bound can also be missing (NIL).
(defun between (value a b)
(<= a value (if b b value)))
Note that Lisp allows the comparison predicate with more than two arguments.
Let's find the category of a storm. The Lisp functions FIND and FIND-IF find things in lists.
(defun storm-category (storm-speed)
(third (find-if (lambda (storm)
(between storm-speed (first storm) (second storm)))
*storm-categories*)))
Let's compute the category for each storm. Since we get a list of (storm wind-speed), we just map over the function which computes the category over the list. We need to return a list of storms and category.
(defun storm-categories (list)
(mapcar (lambda (storm)
(list (first storm)
(storm-category (second storm))))
list))
Now we take the the same list of storms, but use a hash table to keep track of how many storms there were in each category. MAPC is like MAPCAR, but only for the side effect of updating the hash table. ÌNCF increments the count. When we have filled the hash table, we need to map over it with MAPHASH. For each pair of key and value in the table, we just push the pair onto a result list and then we are returning that result.
(defun storm-distribution (storms)
(let ((table (make-hash-table)))
(mapc (lambda (storm)
(incf (gethash (second storm) table 0)))
(storm-categories storms))
(let ((result nil))
(maphash (lambda (key value)
(push (list key value) result))
table)
result)))
Test:
CL-USER 33 > (storm-category 100)
HURRICANE-CAT-2
CL-USER 34 > (storm-categories *storms2004*)
((BONNIE TROPICAL-STORM)
(CHARLEY HURRICANE-CAT-4)
(FRANCES HURRICANE-CAT-4)
(IVAN HURRICANE-CAT-5)
(JEANNE HURRICANE-CAT-3))
CL-USER 35 > (storm-distribution *storms2004*)
((HURRICANE-CAT-5 1)
(HURRICANE-CAT-4 2)
(HURRICANE-CAT-3 1)
(TROPICAL-STORM 1))
Looks fine to me.
Finally finished this problem. the second part is really makes me crazy. I cant't figure out how to use hashtable or assoc list to slove it. Anyway the assignment is done, but I want to know how can I simplify it... Hope u guys can help me . Thanks for your help Joswing, your idea really helps me a lot...
(defconstant *storms2004* '((BONNIE 65)(CHARLEY 150)(FRANCES 145)(IVAN 165)(JEANNE 120)))
(defun storm-category (x) ; for given windspeed return the category
(cond
((and (> x 39) (< x 73) 'tropical-storm))
((and (> x 74) (< x 95) 'hurricane-cat-1))
((and (> x 96) (< x 110) 'hurricane-cat-2))
((and (> x 111) (< x 130) 'hurricane-cat-3))
((and (> x 131) (< x 155) 'hurricane-cat-4))
( t 'hurricane-cat-5)
)
);end storm-category
(defun storm-categories (lst) ;for a list of storm and windspeed return storm's name and wind type
(let ((result nil))
(dolist (x lst (reverse result)) ;
(push
(list (first x) (storm-category (second x)) ) result)
)
)
);end storm-categories
(defun storm-distribution (lst)
(setq stormcategories '(tropical-storm hurricane-cat-1 hurricane-cat-2 hurricane-cat-3 hurricane-cat-4 hurricane-cat-5))
(setq stormlist (storm-categories lst))
(let( (tropicalcount 0)
(hurricane-cat-1count 0)
(hurricane-cat-2count 0)
(hurricane-cat-3count 0)
(hurricane-cat-4count 0)
(hurricane-cat-5count 0)
(result nil)
)
(dolist (y stormlist )
(cond
((eql (second y) 'tropical-storm) (setq tropicalcount (+ tropicalcount 1)))
((eql (second y) 'hurricane-cat-1) (setq hurricane-cat-1count (+ hurricane-cat-1count 1)))
((eql (second y) 'hurricane-cat-2) (setq hurricane-cat-2count (+ hurricane-cat-2count 1)))
((eql (second y) 'hurricane-cat-3) (setq hurricane-cat-3count (+ hurricane-cat-3count 1)))
((eql (second y) 'hurricane-cat-4) (setq hurricane-cat-4count (+ hurricane-cat-4count 1)))
((eql (second y) 'hurricane-cat-5)(setq hurricane-cat-5count (+ hurricane-cat-5count 1)))
)
);ebd dolist
(push
(list (list 'tropicalstorm tropicalcount )
(list 'hurricane-cat-1 hurricane-cat-1count)
(list 'hurricane-cat-2 hurricane-cat-2count )
(list 'hurricane-cat-3 hurricane-cat-3count )
(list 'hurricane-cat-4 hurricane-cat-4count )
(list 'hurricane-cat-5 hurricane-cat-5count )
) ;end list
result) ;end push
);end let
);end distribution
I've done the Graham Common Lisp Chapter 5 Exercise 5, which requires a function that takes an object X and a vector V, and returns a list of all the objects that immediately precede X in V.
It works like:
> (preceders #\a "abracadabra")
(#\c #\d #r)
I have done the recursive version:
(defun preceders (obj vec &optional (result nil) &key (startt 0))
(let ((l (length vec)))
(cond ((null (position obj vec :start startt :end l)) result)
((= (position obj vec :start startt :end l) 0)
(preceders obj vec result
:startt (1+ (position obj vec :start startt :end l))))
((> (position obj vec :start startt :end l) 0)
(cons (elt vec (1- (position obj vec :start startt :end l)))
(preceders obj vec result
:startt (1+ (position obj vec
:start startt
:end l))))))))
It works correctly, but my teachers gives me the following critique:
"This calls length repeatedly. Not so bad with vectors, but still unnecessary. More efficient and more flexible (for the user) code is to define this like other sequence processing functions. Use :start and :end keyword parameters, the way the other sequence functions do, with the same default initial values. length should need to be called at most once."
I am consulting the Common Lisp textbook and google, but there seem to be of little help on this bit: I don't know what he means by "using :start and :end keyword parameters", and I have no clue of how to "call length just once". I would be grateful if you guys could give me some idea how on to refine my code to meet the requirement that my teacher posted.
UPDATE:
Now I have come up with the following code:
(defun preceders (obj vec
&optional (result nil)
&key (start 0) (end (length vec)) (test #'eql))
(let ((pos (position obj vec :start start :end end :test test)))
(cond ((null pos) result)
((zerop pos) (preceders obj vec result
:start (1+ pos) :end end :test test))
(t (preceders obj vec (cons (elt vec (1- pos)) result)
:start (1+ pos) :end end :test test)))))
I get this critique:
"When you have a complex recursive call that is repeated identically in more than one branch, it's often simpler to do the call first, save it in a local variable, and then use the variable in a much simpler IF or COND."
Also,for my iterative version of the function:
(defun preceders (obj vec)
(do ((i 0 (1+ i))
(r nil (if (and (eql (aref vec i) obj)
(> i 0))
(cons (aref vec (1- i)) r)
r)))
((eql i (length vec)) (reverse r))))
I get the critique
"Start the DO at a better point and remove the repeated > 0 test"
a typical parameter list for such a function would be:
(defun preceders (item vector
&key (start 0) (end (length vector))
(test #'eql))
...
)
As you can see it has START and END parameters.
TEST is the default comparision function. Use (funcall test item (aref vector i)).
Often there is also a KEY parameter...
LENGTH is called repeatedly for every recursive call of PRECEDERS.
I would do the non-recursive version and move two indexes over the vector: one for the first item and one for the next item. Whenever the next item is EQL to the item you are looking for, then push the first item on to a result list (if it is not member there).
For the recursive version, I would write a second function that gets called by PRECEDERS, which takes two index variables starting with 0 and 1, and use that. I would not call POSITION. Usually this function is a local function via LABELS inside PRECEDERS, but to make it a bit easier to write, the helper function can be outside, too.
(defun preceders (item vector
&key (start 0) (end (length vector))
(test #'eql))
(preceders-aux item vector start end test start (1+ start) nil))
(defun preceders-aux (item vector start end test pos0 pos1 result)
(if (>= pos1 end)
result
...
))
Does that help?
Here is the iterative version using LOOP:
(defun preceders (item vector
&key (start 0) (end (length vector))
(test #'eql))
(let ((result nil))
(loop for i from (1+ start) below end
when (funcall test item (aref vector i))
do (pushnew (aref vector (1- i)) result))
(nreverse result)))
Since you already have a solution that's working, I'll amplifiy Rainer Joswig's solution, mainly to make related stylistic comments.
(defun preceders (obj seq &key (start 0) (end (length seq)) (test #'eql))
(%preceders obj seq nil start end test))
The main reason to have separate helper function (which I call %PRECEDERS, a common convention for indicating that a function is "private") is to eliminate the optional argument for the result. Using optional arguments that way in general is fine, but optional and keyword arguments play horribly together, and having both in a single function is a extremely efficient way to create all sorts of hard to debug errors.
It's a matter of taste whether to make the helper function global (using DEFUN) or local (using LABELS). I prefer making it global since it means less indentation and easier interactive debugging. YMMV.
A possible implementation of the helper function is:
(defun %preceders (obj seq result start end test)
(let ((pos (position obj seq :start start :end end :test test)))
;; Use a local binding for POS, to make it clear that you want the
;; same thing every time, and to cache the result of a potentially
;; expensive operation.
(cond ((null pos) (delete-duplicates (nreverse result) :test test))
((zerop pos) (%preceders obj seq result (1+ pos) end test))
;; I like ZEROP better than (= 0 ...). YMMV.
(t (%preceders obj seq
(cons (elt seq (1- pos)) result)
;; The other little bit of work to make things
;; tail-recursive.
(1+ pos) end test)))))
Also, after all that, I think I should point out that I also agree with Rainer's advice to do this with an explicit loop instead of recursion, provided that doing it recursively isn't part of the exercise.
EDIT: I switched to the more common "%" convention for the helper function. Usually whatever convention you use just augments the fact that you only explicitly export the functions that make up your public interface, but some standard functions and macros use a trailing "*" to indicate variant functionality.
I changed things to delete duplicated preceders using the standard DELETE-DUPLICATES function. This has the potential to be much (i.e., exponentially) faster than repeated uses of ADJOIN or PUSHNEW, since it can use a hashed set representation internally, at least for common test functions like EQ, EQL and EQUAL.
A slightly modofied variant of Rainer's loop version:
(defun preceders (item vector
&key (start 0) (end (length vector))
(test #'eql))
(delete-duplicates
(loop
for index from (1+ start) below end
for element = (aref vector index)
and previous-element = (aref vector (1- index)) then element
when (funcall test item element)
collect previous-element)))
This makes more use of the loop directives, and among other things only accesses each element in the vector once (we keep the previous element in the previous-element variable).
Answer for your first UPDATE.
first question:
see this
(if (foo)
(bar (+ 1 baz))
(bar baz))
That's the same as:
(bar (if (foo)
(+ 1 baz)
baz))
or:
(let ((newbaz (if (foo)
(+ 1 baz)
baz)))
(bar newbaz))
Second:
Why not start with I = 1 ?
See also the iterative version in my other answer...
The iterative version proposed by Rainer is very nice, it's compact and more efficient since you traverse the sequence only one time; in contrast to the recursive version which calls position at every iteration and thus traverse the sub-sequence every time. (Edit: I'm sorry, I was completely wrong about this last sentence, see Rainer's comment)
If a recursive version is needed, another approach is to advance the start until it meets the end, collecting the result along its way.
(defun precede (obj vec &key (start 0) (end (length vec)) (test #'eql))
(if (or (null vec) (< end 2)) nil
(%precede-recur obj vec start end test '())))
(defun %precede-recur (obj vec start end test result)
(let ((next (1+ start)))
(if (= next end) (nreverse result)
(let ((newresult (if (funcall test obj (aref vec next))
(adjoin (aref vec start) result)
result)))
(%precede-recur obj vec next end test newresult)))))
Of course this is just another way of expressing the loop version.
test:
[49]> (precede #\a "abracadabra")
(#\r #\c #\d)
[50]> (precede #\a "this is a long sentence that contains more characters")
(#\Space #\h #\t #\r)
[51]> (precede #\s "this is a long sentence that contains more characters")
(#\i #\Space #\n #\r)
Also, I'm interested Robert, did your teacher say why he doesn't like using adjoin or pushnew in a recursive algorithm?