I have a question about a recursive function to draw an image
Yes, it's a homework, but I don't know how to draw that image. What I have so far is:
A function that gives me a list of points(x/y) from a curve((list (x1/y2) (x2/y2)...(xn/yn))
To get a x-coordinate for example I have to write point-x (first lis)
A function I called (zipWith f xs ys)that takes two lists(xs ys) apply the function f and makes a list (for example (zipWith + (list 1 2 3) (list 10 20 30)) -> (list 11 22 33))
A function make-tuple that takes two lists and makes them a tuple (for example:
(make-tuple (list 1 2 3) (list 4 5 6)) -> (tuple (list 1 2 3) (list 4 5 6))
To get the first tuple I have to write (xs1 (tuple (list 1 2 3) (list 4 5 6)) -> (list 1 2 3)
Now to the actual function:
We have to use the function add-line which draws a line from one point to another.
The parameters are image number number number number string
In other words: empty-image x1 y1 x2 y2 "black"
So it starts with an empty-image and draws a line from (x1/y1) to (x2/y2) with the color "black"
And we have to use fold to write the function. So my attempt on this:
;Signature
(: render ((list-of point) -> image))
(define render
(lambda (xs)
(let((tuple-list (zipWith make-tuple xs (rest xs))))
(fold empty-image
add-line
tuple-list))))
What I tried to do was take the list of points and make a list with tuple of points
(list (tuple (x1/y1) (x2/y2)) (tuple (x2/y2) (x3/y3))...(tuple (xn/yn) (xn/yn)))
Now I want to apply add-line with fold to the list of tuples. So that I say, lets take the first tuple (my two points) and apply them to the function add-line. Then take the next tuple and also apply these points to the add-line function (and so on) until my list is empty.
The problem now is, Scheme says add-line expects 6 parameters but found only 2. I know my problem, because add-line don't know where to get the other parameters. So I tried:
(define render
(lambda (xs)
(let((tuple-list (zipWith make-tuple xs (rest xs))))
(fold empty-image (add-line
empty-image
(point-x (xs1 (first tuple-list)))
(point-y (xs1 (first tuple-list)))
(point-x (xs2 (first tuple-list)))
(point-y (xs2 (first tuple-list)))
"black")
tuple-list))))
and know it says "function call: expected a function after the open parenthesis, but received an image"
And again I know my mistake, add-line draws one line, and fold tries to apply that image to the list, but need a function not an image. So my question:
How can I write a recursive function render with add-line and fold, that draws the first line, then get the next points and draws the next line combined with the first one?
(like a recursive add-line function, that calls itself again after drawing a line)
You don't say specifically which language you are using,
but this looks suspicious:
(fold empty-image (add-line ...))
In Racket the way to use fold is:
(foldl f base l)
Here f is a function. In your code you have empty-image.
You need to define define a function say f, that use a tuple to add a line onto the "current" image:
; f : tuple image -> image
(define (f t img)
(add-line img
(point-x (xs1 t))
(point-y (xs1 t))
(point-x (xs2 t))
(point-y (xs2 t))
"black"))
and then
(foldl f empty-image tuple-list)
You might need to tweak a thing or two to get it to work.
Related
I'm working on some numerical computations in Common Lisp and I need to compute a linear combination of several vectors with given numerical coefficients. I'm rewriting a piece of Fortran code, where this can be accomplished by res = a1*vec1 + a2*vec2 + ... + an*vecn. My initial take in CL was to simply write each time something like:
(map 'vector
(lambda (x1 x2 ... xn)
(+ (* x1 a1) (* x2 a2) ... (* xn an)))
vec1 vec2 ... vecn)
But I soon noticed that this pattern would recur over and over again, and so started writing some code to abstract it away. Because the number of vectors and hence the number of lambda's arguments would vary from place to place, I figured a macro would be required. I came up with the following:
(defmacro vec-lin-com (coefficients vectors &key (type 'vector))
(let ((args (loop for v in vectors collect (gensym))))
`(map ',type
(lambda ,args
(+ ,#(mapcar #'(lambda (c a) (list '* c a)) coefficients args)))
,#vectors)))
Macroexpanding the expression:
(vec-lin-com (10 100 1000) (#(1 2 3) #(4 5 6) #(7 8 9)))
yields the seemingly correct expansion:
(MAP 'VECTOR
(LAMBDA (#:G720 #:G721 #:G722)
(+ (* 10 #:G720) (* 100 #:G721) (* 1000 #:G722)))
#(1 2 3) #(4 5 6) #(7 8 9))
So far, so good...
Now, when I try to use it inside a function like this:
(defun vector-linear-combination (coefficients vectors &key (type 'vector))
(vec-lin-com coefficients vectors :type type))
I get a compilation error stating essentially that The value VECTORS is not of type LIST. I'm not sure how to approach this. I feel I'm missing something obvious. Any help will be greatly appreciated.
You've gone into the literal trap. Macros are syntax rewriting so when you pass 3 literal vectors in a syntax list you can iterate on them at compile time, but replacing it with a bindnig to a list is not the same. The macro only gets to see the code and it doesn't know what vectors will eventually be bound to at runtime when it does its thing. You should perhaps make it a function instead:
(defun vec-lin-com (coefficients vectors &key (type 'vector))
(apply #'map
type
(lambda (&rest values)
(loop :for coefficient :in coefficients
:for value :in values
:sum (* coefficient value)))
vectors))
Now you initial test won't work since you passed syntax and not lists. you need to quote literals:
(vec-lin-com '(10 100 1000) '(#(1 2 3) #(4 5 6) #(7 8 9)))
; ==> #(7410 8520 9630)
(defparameter *coefficients* '(10 100 1000))
(defparameter *test* '(#(1 2 3) #(4 5 6) #(7 8 9)))
(vec-lin-com *coefficients* *test*)
; ==> #(7410 8520 9630)
Now you could make this a macro, but most of the job would have been done by the expansion and not the macro so basically you macro would expand to similar code to what my function is doing.
Remember that macros are expanded at compile-time, so the expression ,#(mapcar #'(lambda (c a) (list '* c a)) coefficients args) has to be meaningful at compile-time. In this case, all that mapcar gets for coefficients and args are the symbols coefficients and vectors from the source code.
If you want to be able to call vec-lin-com with an unknown set of arguments (unknown at compile-time, that is), you'll want to define it as a function. It sounds like the main problem you're having is getting the arguments to + correctly ordered. There's a trick using apply and map to transpose a matrix that may help.
(defun vec-lin-com (coefficients vectors)
(labels
((scale-vector (scalar vector)
(map 'vector #'(lambda (elt) (* scalar elt)) vector))
(add-vectors (vectors)
(apply #'map 'vector #'+ vectors)))
(let ((scaled-vectors (mapcar #'scale-vector coefficients vectors)))
(add-vectors scaled-vectors))))
This isn't the most efficient code in the world; it does a lot of unnecessary consing. But it is effective, and if you find this to be a bottleneck you can write more efficient versions, including some that can take advantage of compile-time constants.
I am writing a function in Scheme with Advanced Student settings. The function traverses through graph G and looks if there is a path between vertex X and Y. It "kinda" works, but not in all cases. I know where the problem lies, but I am not sure how to fix it. First I look if the vertex X I am looking on has been visited, if not I continue and mark it as visited. Then there is function find-adju. That function returns list of all of neighbours for given vertex. For example if I had a graph like this:
(define-struct graph (vertices edges))
(define-struct vertice (name visited))
(define-struct edge (start-vertice end-vertice length))
(define vertices-list
(list (make-vertice 0 0)
(make-vertice 1 0)
(make-vertice 2 0)
(make-vertice 3 0)
(make-vertice 4 0)
)
)
(define edges-list
(list (make-edge 0 1 0)
(make-edge 0 2 0)
(make-edge 1 3 0)
(make-edge 2 0 0)
(make-edge 2 4 0)
(make-edge 4 2 0)
)
)
(define G (make-graf vertices-list edge-list))
(traverse-graph? 0 4 G)
Then for given vertex 0 it would return list(1 2). Next I look at the list and ask, if my desired vertex Y is in it. If not, look again recursively at the first item in the list. But in doing so I lose information about all the other neighbours. In the same case, it would look at vertex 1, find all of his neighbours and then the procedure would quit, because it did not find a way. But the vertex 2 then remains unvisited. How can I make the procesure look at every item in the lsit and not just the first one?
(define (traverse-graph X Y G)
(cond
[(not(eq? (vertex-visited (find-vertex X (graph-vertices G))) VISITED))
(begin
(set-vertex-visited! (find-vertex X (graph-vertices G)) VISITED)
(cond
[(member Y (find-adju X (graph-edges G))) #t]
[(not (empty? (find-adju X (graph-edges G)))) (traverse-graph (car (find-adju X (graph-edges G))) Y G) ]
[else #f]
)
)
]
[else #f]
)
)
I thought of maybe returning the whole list with cdr instead of car to the traverse-function, but I don't know how to implement that. And how would I deal with the first step where X is a number and not a list.
EDIT:
I tried adding for-each which seems to be working ok, but the result is not giving me anything. No true or false. If I debug it step by step, I see that it is probably traversing correctly but when it reaches the [(member condition, it stops without returning anything, even when the condition is true.
(define (traverse-graph X Y G)
(cond
[(not(eq? (vertex-visited (find-vertex X (graph-vertices G))) VISITED))
(begin
(set-vertex-visited! (find-vertex X (graph-vertices G)) VISITED)
(cond
[(member Y (find-adju X (graph-edges G))) #t]
[(not (empty? (find-adju X (graph-edges G))))
(for-each (lambda (h)
(traverse-graph h Y G)
) (find-adju X (graph-edges G))
)
]
[else #f]
)
)
]
[else #f]
)
)
You were on the right path with for-each, but that function is an imperative construct. For each edge in your list it says "do this, do that", but does not keep any value. You would have more luck with map, which iterates over the list, and aggregates the results in a list.
With map, the result of your traverse-graph will be a tree with the shape of a depth-first-search traversal:
'(result0 (result1 (result3))
(result2 (result4)))
You could use (apply append (map (lambda …) (find-adju …)) to append the list of lists at each step, and prepend with cons the result for the current node. Don't forget to return a list containing a single element for the leaf nodes of your traversale, i.e use '(#t) and '(#f). This has however a big drawback the time complexity is O(N²) in the worst case. Imagine a graph where each node has two children: a leaf as its right child, and the rest of the graph as its left child:
(→ 0 2) (→ 0 1)
(→ 2 4) (→ 2 3)
(→ 4 6) (→ 4 5)
(→ 6 8) (→ 6 7)
(→ 8 10) (→ 8 9)
…
(→ 96 98) (→ 96 97)
(→ 98 100) (→ 98 99)
With that graph, your traversal will start drilling down the left edges until it reaches the leftmost node (100),
then return from that to node 98, go down to 99, and back up to 98, where it will append '(result100) to '(result99) and prepend result98,
then it will move back up to 96, examine 97, move back to 96, and append '(result98 result100 result99) to '(result97) and prependresult96`,
…
then it will move back up to 0, examine 1, move back to 0, and append '(… many results here …) to '(result1), and prepend result0.
Since append has to copy all the elements from the prefix, appending a list of length n to a list of length m will cost n operations (the second list is simply pointed to, and doesn't need to be copied, as the tail it forms is identical to the original whole second list), i.e it costs O(n) operations. The sequence of calls to append will be:
append 1 element to 1 element
append 3 elements to 1 element
append 5 elements to 1 element
append 7 elements to 1 element
append 9 elements to 1 element
…
append 99 elements to 1 element
So the total cost is 1+3+5+…+N, where N is the total number of nodes, which is roughly equivalent to N² times constant factor, hence the O(n²), which means that for a large number of nodes, it will be very slow. More about this at wikipedia.
To avoid the O(N²) cost, you can use an accumulator: each step will prepend a single item to the accumulator, and pass it around. This means that when handling a node, you have to give the current accumulator to its first neighbour, get back the modified accumulator for that whole sub-tree, pass that to the second neighbour, get back a new modified accumulator, pass that to the third neighbour, etc.
For that, you could write your own recursive function over the list, taking the latest accumulator and the list as an argument, and making a recursive call with the modified accumulator (obtained by processing the whole sub-tree), and the tail of the list.
You could also use the foldl function which abstracts over this pattern. The node-processing function will then follow this structure:
(define (process node accumulator)
(foldl ; the function applied to each neighbour of the list,
; it is passed the neighbour and the accumulator returned
; by the previous iteration
(lambda (neighbour latest-accumulator)
(if (visited? neighbour)
(process neighbour latest-accumulator)
latest-accumulator)) ; return unchanged
; initial accumulator for the first iteration,
; we already prepend the result for the current node,
; but that could be done afterwards, by prepending
; to the final result of `foldl`.
(cons (compute-result-for node) accumulator)
; the list of neighbours:
(neighbours-of node)))
Since this does never append lists, instead just prepending a single result at each step, it has a complexity of O(N) (without counting the cost of the neighbours-of function, see the note on hash tables and sets below). The flow of data is a bit convoluted though, sadly there's no better option with immutable data structures.
In your specific case, since you return a boolean, you could also simply use ormap, which will iterate over the list and return #t if the lambda returned #t for any element.
Does this have the O(N²) complexity like map? Think about why it does not.
As a side note, you should use #f and #t instead of 0 and VISITED, or #f and 'visited (the quoted ' symbol visited, which is considered true in an if statement, like all values other than #f).
For better performance, use hash tables and sets to store the edges, as looking for the edges in a list will cost a lot if there are many edges.
Finally, I would suggest putting the closing parenthesis of a block of code at the end of the last line, instead of having them alone on their line. This is the common practice in Scheme, Racket and most other Lisp variants, and makes the code more readable IMHO.
"but when it reaches the [(member condition, it stops without returning anything, even when the condition is true."
Check first if the list produced by
(find-adju X (graph-edges G)))
is empty. Then check if the list is non-empty and if Y is in that list. Then have an else case, where the list is non-empty but Y is not in the list of immediate neighbors.
So i was asked to do a function i LISP that calculates the average of any given numbers. The way i was asked to do this was by using the &rest parameter. so i came up with this :
(defun average (a &rest b)
(cond ((null a) nil)
((null b) a)
(t (+ (car b) (average a (cdr b))))))
Now i know this is incorrect because the (cdr b) returns a list with a list inside so when i do (car b) it never returns an atom and so it never adds (+)
And that is my first question:
How can i call the CDR of a &rest parameter and get only one list instead of a list inside a list ?
Now there is other thing :
When i run this function and give values to the &rest, say (average 1 2 3 4 5) it gives me stackoverflow error. I traced the funcion and i saw that it was stuck in a loop, always calling the function with the (cdr b) witch is null and so it loops there.
My question is:
If i have a stopping condition: ( (null b) a) , shouldnt the program stop when b is null and add "a" to the + operation ? why does it start an infinite loop ?
EDIT: I know the function only does the + operation, i know i have to divide by the length of the b list + 1, but since i got this error i'd like to solve it first.
(defun average (a &rest b)
; ...
)
When you call this with (average 1 2 3 4) then inside the function the symbol a will be bound to 1 and the symbol b to the proper list (2 3 4).
So, inside average, (car b) will give you the first of the rest parameters, and (cdr b) will give you the rest of the rest parameters.
But when you then recursively call (average a (cdr b)), then you call it with only two arguments, no matter how many parameters where given to the function in the first place. In our example, it's the same as (average 1 '(3 4)).
More importantly, the second argument is now a list. Thus, in the second call to average, the symbols will be bound as follows:
a = 1
b = ((3 4))
b is a list with only a single element: Another list. This is why you'll get an error when passing (car b) as argument to +.
Now there is other thing : When i run this function and give values to the &rest, say (average 1 2 3 4 5) it gives me stackoverflow error. I traced the funcion and i saw that it was stuck in a loop, always calling the function with the (cdr b) witch is null and so it loops there. My question is:
If i have a stopping condition: ( (null b) a) , shouldnt the program stop when b is null and add "a" to the + operation ? why does it start an infinite loop ?
(null b) will only be truthy when b is the empty list. But when you call (average a '()), then b will be bound to (()), that is a list containing the empty list.
Solving the issue that you only pass exactly two arguments on the following calls can be done with apply: It takes the function as well as a list of parameters to call it with: (appply #'average (cons a (cdr b)))
Now tackling your original goal of writing an average function: Computing the average consists of two tasks:
Compute the sum of all elements.
Divide that with the number of all elements.
You could write your own function to recursively add all elements to solve the first part (do it!), but there's already such a function:
(+ 1 2) ; Sum of two elements
(+ 1 2 3) ; Sum of three elements
(apply #'+ '(1 2 3)) ; same as above
(apply #'+ some-list) ; Summing up all elements from some-list
Thus your average is simply
(defun average (&rest parameters)
(if parameters ; don't divide by 0 on empty list
(/ (apply #'+ parameters) (length parameters))
0))
As a final note: You shouldn't use car and cdr when working with lists. Better use the more descriptive names first and rest.
If performance is critical to you, it's probably best to fold the parameters (using reduce which might be optimized):
(defun average (&rest parameters)
(if parameters
(let ((accum
(reduce #'(lambda (state value)
(list (+ (first state) value) ;; using setf is probably even better, performance wise.
(1+ (second state))))
parameters
:initial-value (list 0 0))))
(/ (first accum) (second accum)))
0))
(Live demo)
#' is a reader macro, specifically one of the standard dispatching macro characters, and as such an abbreviation for (function ...)
Just define average*, which calls the usual average function.
(defun average* (&rest numbers)
(average numbers))
I think that Rainer Joswig's answer is pretty good advice: it's easier to first define a version that takes a simple list argument, and then define the &rest version in terms of it. This is a nice opportunity to mention spreadable arglists, though. They're a nice technique that can make your library code more convenient to use.
In most common form, the Common Lisp function apply takes a function designator and a list of arguments. You can do, for instance,
(apply 'cons '(1 2))
;;=> (1 . 2)
If you check the docs, though, apply actually accepts a spreadable arglist designator as an &rest argument. That's a list whose last element must be a list, and that represents a list of all the elements of the list except the last followed by all the elements in that final list. E.g.,
(apply 'cons 1 '(2))
;;=> (1 . 2)
because the spreadable arglist is (1 (2)), so the actual arguments (1 2). It's easy to write a utility to unspread a spreadable arglist designator:
(defun unspread-arglist (spread-arglist)
(reduce 'cons spread-arglist :from-end t))
(unspread-arglist '(1 2 3 (4 5 6)))
;;=> (1 2 3 4 5 6)
(unspread-arglist '((1 2 3)))
;;=> (1 2 3)
Now you can write an average* function that takes one of those (which, among other things, gets you the behavior, just like with apply, that you can pass a plain list):
(defun %average (args)
"Returns the average of a list of numbers."
(do ((sum 0 (+ sum (pop args)))
(length 0 (1+ length)))
((endp args) (/ sum length))))
(defun average* (&rest spreadable-arglist)
(%average (unspread-arglist spreadable-arglist)))
(float (average* 1 2 '(5 5)))
;;=> 3.25
(float (average* '(1 2 5)))
;;=> 2.66..
Now you can write average as a function that takes a &rest argument and just passes it to average*:
(defun average (&rest args)
(average* args))
(float (average 1 2 5 5))
;;=> 3.5
(float (average 1 2 5))
;;=> 2.66..
write a scheme function workit that takes a predicate and a list of integers as arguments. the function should multiply each item in the list that satisfies the predicate by 2 and adds the results. For example::
(workit even? '(1 2 3 4 5 6)) ==> 4+8+12=24
(workit odd? '(1 2 3 4 5 6)) ==> 2+6+10=18
You may not use map, remove, filter, or any other higher order function.
Could someone at least help me get a head start on this? Decided to learn Scheme for a job that I am interested in applying for.... Any help would be great! Thanks
First define even?
(define (even? x) (= 0 (modulo x 2)))
You can define odd? in terms of not even
(define (odd? x) (not (even? x)))
Your workit function is pretty self-explanatory
(define (workit predicate xs)
(define (iter sum xs)
(cond ((empty? xs) sum)
((predicate (first xs)) (iter (+ sum (* 2 (first xs))) (rest xs)))
(else (iter sum (rest xs)))))
(iter 0 xs))
I defined an inner iter function to step through the list of provided numbers, xs, while keeping track of the output, sum.
If the list we're iterating through is empty?, we're done, so return the sum
Else, if (predicate x) is true, add (* 2 x) to the sum and continue iteration
Otherwise, the predicate is false, do not alter the sum for this iteration
I chose to use the auxiliary iter function in order to achieve proper tail recursion. This allows workit to operate in constant space.
Outputs
(print (workit even? '(1 2 3 4 5 6))) ;; => 24
(print (workit odd? '(1 2 3 4 5 6))) ;; => 18
If there are no elements in the list, the workit of the list is some base
value.
If the first element satisfies some condition, then the workit of the list is the result of some operation involving that first element, and the workit of the remainder of the list.
If the first element does not satisfy the condition, then the workit of the list is simply the workit of the remainder of the list.
Note that each time workit is called recursively (as in the second and third cases) the list is the remainder of the list in the the previous call.
I have the following variadic function (define doSomething (lambda (x . rest) .... The function is called by using numbers, for example: (doSomething 1 2 3 4 5) (so with that call x would be 1 and rest would be (2 3 4 5)).
When I try to recursively call the function and put the second number (2) as x and rest as (3 4 5) I somehow receive the rest parameter as a list of list: ((3 4 5)).
This is how I currently try to call the function again:
(+ x (doSomething (car rest) (cdr rest)))
It is worth mentioning that I'm using Pretty Big. Please advise, thanks.
So you're mix and matching what rest is, in your first call
(doSomething 1 2 3 4 5) ; x = 1 rest = '(2 3 4 5)
In your subsequent calls you'll end up with
(doSomething (car rest) (cdr rest)) ; x=2 rest = '((3 4 5))
because rest is a variadic argument, so it takes everything after the first argument and makes it a list called rest for you, hence the double-listing. You'll probably want to be using apply or something, ie something like:
(define doSomething (lambda (x . rest)
(display x)
(if (not (null? rest))
(apply doSomething rest)
#f)))