Search code examples
recursionschemedrawfold

draw-function with fold and add-line?


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)


Solution

  • 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.