Shoelace formula in racket - list

I am having problems in finding a way to recursively calculate the area.
(check-expect(signed-area(list (make-posn 1 2)(make-posn 3 4)(make-posn 5 6)(make-posn 1 6)))8)
(check-expect(signed-area(list (make-posn 1 2)(make-posn 11 3)(make-posn 12 9)(make-posn 2 10)))70)
(define (signed-area lop)
(cond
[(< 3 (length lop)) 0]
[else
(abs (/ (+(-(* (posn-x (first lop)) (posn-y (second lop)))
(* (posn-x(second lop)) (posn-y(first lop))))
(-(* (posn-x (second lop)) (posn-y (third lop)))
(* (posn-x(third lop)) (posn-y(second lop))))
(-(* (posn-x (third lop)) (posn-y (fourth lop)))
(* (posn-x(fourth lop)) (posn-y(third lop))))
(-(* (posn-x (fourth lop)) (posn-y (first lop)))
(* (posn-x(first lop)) (posn-y(fourth lop)))))
2))]))
I am out of ideas on how to recursively go through the list, and remove the first posn after it went through the list. Since the code I have is limited to 4 points and I have to make this to be at least 3 points

Solution I - direct recursion
However, the problem is the absolute function at the end over the entire formula.
For this to be executed at the very final on the entire sum, you have to put your function into the outer function and apply abs on the function-call:
(define (signed-area plist)
(define (.signed-area plist)
(cond ((< (length plist) 3) 0)
(else (+
(/ (- (* (first plist) (fourth plist))
(* (second plist) (third plist)))
2)
(.signed-area (cddr plist))))))
(abs (.signed-area plist))) ;; final absolute
Instead of dividing by to for every summand, you can do it also at the
very end on the entire absolute sum. So, very very minimally more efficient - but in the praxis totally negligible improvement.
(define (signed-area plist)
(define (.signed-area plist)
(cond ((< (length plist) 3) 0)
(else (+
(- (* (first plist) (fourth plist))
(* (second plist) (third plist)))
(.signed-area (cddr plist))))))
(* (/ 1 2) (abs (.signed-area plist))))
Solution II - tail-call recursion
This is a technique which is memory saving and avoids nesting of recursive calls for the interpreter. So generally regarded as best practice.
In addition, you can more clearly see what happens between the steps - because
you have just to concentrate on acc and what is done on it at each recursion step - then you understand the formula/procedure undertaken on the results of each single step. Because of these two reasons, tail-call recursion is the preferred method for lisp-programmers to formulate recursive functions.
(define (signed-area plist)
(define (.signed-area plist acc) ; introduce accumulator
(cond ((< (length plist) 3) (* (/ 1 2) (abs acc)))
(else (.signed-area (cddr plist) ; in next round remove first pair
(+ (- (* (first plist) (fourth plist))
(* (second plist) (third plist)))
acc))))) ; add shoelace product to accumulator
(.signed-area plist 0)) ; call inner recursive function with accumulator start value 0
;
Test
All three function definitions give the correct result 2:
(signed-area (list 1 2 3 4 5 6))
;; => 2
For checking/testing, calculate by hand the example:
;; to check, calculate shoelace by hand:
;; visualize:
;; 1 2
;; 3 4
;; 5 6
;
;; and then calculate:
(* (/ 1 2)
(abs (+ (- (* 1 4)
(* 2 3))
(- (* 3 6)
(* 4 5)))))
;; => 2
For list-of-posn
(define (signed-area list-of-posn)
(define (.signed-area list-of-posn acc) ; introduce accumulator
(cond ((< (length list-of-posn) 2) (* (/ 1 2) (abs acc)))
(else (.signed-area (cdr list-of-posn) ; in next round remove first posn
(+ (- (* (posn-x (first list-of-posn)) (posn-y (second list-of-posn)))
(* (posn-x (second list-of-posn)) (posn-y (first list-of-posn))))
acc))))) ; add shoelace product to accumulator
(.signed-area list-of-posn 0)) ; call inner recursive function with accumulator start value 0

Related

DrRacket Using accumulator as List-ref index

I am trying to write a function that take a list and iterates over each element in the list if the number is even I want that number to be added to the previous number in the list.
I was thinking an accumulator will count up from 0 with each iteration giving a position for each element in the list.
If the number in the list is even I want to add that number to the previous number in the list.
Hence why I am trying to use the accumulator as an index for list-ref. I don't know how to write it to get the accumulator value for the previous iteration (+ i (list-ref a-list(- acc 1)))?
(define loopl (lambda (l)
(for/fold
([acc 0])([i l])
(cond
[(even? i)(+ i (list-ref (- acc 1) l))]
enter image description here
The question is not quite clear about the value to be returned by this function:
this answer assumes that it is a total of even elements together with their previous elements.
The function is developed using the
HtDF (How to Design Functions)
design method with a BSL (Beginning Student language) in DrRacket.
Start with a stub, incorporating signature and purpose, and a minimal "check-expect" example:
(Note: layout differs slightly from HtDF conventions)
(define (sum-evens-with-prev xs) ;; (Listof Integer) -> Integer ; *stub define* ;; *signature*
;; produce total of each even x with its previous element ; *purpose statement*
0) ; *stub body* (a valid result)
(check-expect (sum-evens-with-prev '()) 0) ; *minimal example*
This can be run in DrRacket:
Welcome to DrRacket, version 8.4 [cs].
Language: Beginning Student with List Abbreviations
The test passed!
>
The next steps in HtDF are template and inventory. For a function with one list
argument the "natural recursion" list template is likely to be appropriate;
(define (fn xs) ;; (Listof X) -> Y ; *template*
(cond ;
[(empty? xs) ... ] #|base case|# ;; Y ;
[else (... #|something|# ;; X Y -> Y ;
(first xs) (fn (rest xs))) ])) ;
With this template the function and the next tests become:
(define (sum-evens-with-prev xs) ;; (Listof Number) -> Number
;; produce total of each even x with its previous element (prev of first is 0)
(cond
[(empty? xs) 0 ] #|base case: from minimal example|#
[else (error "with arguments: " #|something: ?|#
(first xs) (sum-evens-with-prev (rest xs))) ]))
(check-expect (sum-evens-with-prev '(1)) 0)
(check-expect (sum-evens-with-prev '(2)) 2)
These tests fail, but the error messages and purpose statement suggest what is required:
the (... #|something|# from the template has to choose whether to add (first xs):
(define (sum-evens-with-prev xs) ;; (Listof Integer) -> Integer
;; produce total of each even x with its previous element (prev of first is 0)
(cond
[(empty? xs) 0 ]
[else
(if (even? (first xs))
(+ (first xs) (sum-evens-with-prev (rest xs)))
(sum-evens-with-prev (rest xs))) ]))
Now all 3 tests pass! Time for more check-expects (note: careful introduction of
check-expects is a way of clarifying ones understanding of the requirements, and
points one to the code to be added):
(check-expect (sum-evens-with-prev '(1 1)) 0)
(check-expect (sum-evens-with-prev '(1 2)) 3)
Ran 5 tests.
1 of the 5 tests failed.
Check failures:
Actual value 2 differs from 3, the expected value.
sum-evens-with-prev needs the prev value to include in the even? case:
make it available by introducing it as an argument (renaming the function), add
the appropriate arguments to the recursive calls, the function now just calls
sum-evens-and-prev:
(define (sum-evens-and-prev xs prev) ;; (Listof Integer) Integer -> Integer
;; produce total of each even x and prev
(cond
[(empty? xs) 0 ]
[else
(if (even? (first xs))
(+ prev (first xs) (sum-evens-and-prev (rest xs) (first xs)))
(sum-evens-and-prev (rest xs) (first xs))) ]))
(define (sum-evens-with-prev xs) ;; (Listof Integer) -> Integer
;; produce total of each even x with its previous element (prev of first is 0)
(sum-evens-and-prev xs 0))
(just add some more tests, and all is well :)
(check-expect (sum-evens-with-prev '(0 2)) 2)
(check-expect (sum-evens-with-prev '(2 1)) 2)
(check-expect (sum-evens-with-prev '(1 3)) 0)
(check-expect (sum-evens-with-prev '(2 2)) 6)
(check-expect (sum-evens-with-prev '(1 2 3 4)) 10)
(check-expect (sum-evens-with-prev '(1 2 3 3 5 6 6)) 26)
Welcome to DrRacket, version 8.4 [cs].
Language: Beginning Student with List Abbreviations.
All 11 tests passed!
>
The (for/fold) form requires a (values) clause, and it is in that which you would put the conditional form.
Assuming you want only the new list as the return value, you would also want a #:result clause following the iteration variables.
(define loopl
(lambda (l)
(for/fold
([index 0]
[acc '()]
#:result acc)
([i l])
(values [+ index 1]
[append acc
(if (and (> index 0)
(even? i))
(list (+ i (list-ref l (- index 1))))
(list i))]))))
This should give the correct answer.
You almost never want to repeatedly call list-ref in a loop: that makes for horrible performance. Remember that (list-ref l i) takes time proportional to i: in your case you're going to be calling list-ref with the index being, potentially 0, 1, ..., and that going to result in quadratic performance, which is bad.
Instead there's a neat trick if you want to iterate over elements of a list offset by a fixed amount (here 1): iterate over two lists: the list itself and its tail.
In addition you need to check that the first element of the list is not even (because there is no previous element in that case, so this is an error).
Finally I'm not entirely sure what you wanted to return from the function: I'm assuming it's the sum.
(define (accum-even-previouses l)
(unless (not (even? (first l)))
;; if the first elt is even this is an error
(error 'accum-even-previouses "even first elt"))
(for/fold ([accum 0])
([this (in-list (rest l))]
[previous (in-list l)])
(+ accum (if (even? this)
(+ this previous)
0))))

Count the number of times an element is greater than its previous element in a list

I am trying to use the ability to have multiple "then-expressions" for a conditional in cond but I've yet to be successful in that. The goal is to have a function take in a list and spit out the count.
(define (countInc aList)
(let ((count 0))
(lambda ()
(cond
[(= (length aList) 0) '()]
[(> (second aList) (first aList)) (set! count (+ count 1)) (countInc (rest aList))]
(else (countInc (rest aList)))))))
(check-expect (countInc '(1 2 3 4 5 6)) 5)
To explain, answer is 5 because 2 > 1, 3 > 2, 4 > 3, 5 > 4, and 6 > 5.
Notice that your base case is incorrect: you're returning an empty list, shouldn't we be returning the counter? By the way, your procedure is actually returning a lambda with no arguments, that's not what you want to do.
Also: you should never use length for determining if a list is empty, and in general you should avoid using set! unless strictly necessary - Scheme favors a functional-programming style.
What you want to do can be written without mutating state variables, the trick is to keep track of the previous element while traversing the list - and beware of the many edge cases!
(define (countInc lst)
; edge cases
(if (or (empty? lst) (empty? (rest lst)))
0
; use a named let or a helper procedure
(let loop ((prev (first lst))
(lst (rest lst)))
(cond ((empty? (rest lst)) ; base case
(if (> (first lst) prev) 1 0))
((> (first lst) prev) ; found one, count it
(+ 1 (loop (first lst) (rest lst))))
(else ; skip this one
(loop (first lst) (rest lst)))))))
This works fine even for the edge cases, I've provided tests for them:
(countInc '())
=> 0
(countInc '(1))
=> 0
(countInc '(2 1))
=> 0
(countInc '(1 2))
=> 1
(countInc '(4 1 3 2 5 6))
=> 3
(countInc '(1 2 3 4 5 6))
=> 5

how to make a recursive racket list that, from the input list, outputs its decreasing to 1 for every element in the list (e.g. ('3 2) outputs ('32121)

****What I tried****
(define(help num)
(if(= num 1)
num
(cons(num (help( - num 1))))))
;i called this defination in the bottom one
(define (list-expand L)
(cond
[(empty? L)'()]
[(=(car L)1)(cons(car L)(list-expand (cdr L)))]
[(>(car L)1) (cons(help(car L)(list-expand(cdr L))))]))
In the help procedure, the base case is incorrect - if the output is a list then you must return a list. And in the recursive step, num is not a procedure, so it must not be surrounded by brackets:
(define (help num)
(if (<= num 0)
'()
(cons num (help (- num 1)))))
And in list-expand, both recursive steps are incorrect. You just need to test whether the list is empty or not, calling help with the correct number of parameters; use append to combine the results, because we're concatenating sublists together:
(define (list-expand L)
(if (empty? L)
'()
(append (help (car L)) (list-expand (cdr L)))))
That should work as expected, but please spend some time studying Scheme's syntax, you still have trouble with the basics, for instance, when and where to use brackets...
(list-expand '(3 2))
=> '(3 2 1 2 1)
Just for fun - a non-recursive solution in Racket:
(append-map (lambda (n) (stream->list (in-range n 0 -1))) '(3 2))
;; or:
(append-map (lambda (n) (for/list ((x (in-range n 0 -1))) x)) '(3 2))
Returning:
'(3 2 1 2 1)

infinite sequence scheme to make infinite sequence

I have a project in scheme in which I need to implement an infinite sequence of numbers. I can't use any scheme-built-in complex functions, and I just do not know how to make my sequence infinite without program crashing in infinite loop. I don't have to really output it, but I need to be able to use it.
(seq n) ;;output: n,n+1,n+2,n+3.... to infinity (seq 5) ->5,6,7,8,9...
Right now I did a sequence until n+7, but I need this to infinity:
(define (seq n)
(define (asc-order LIST counter)
(cond ((= counter (+ n 7)) LIST)
(else (asc-order (append LIST (cons (+ counter 1) '()))
(+ counter 1)))))
(asc-order '() (- n 1))
)
IO example (It works, but I need it infinite sequence):
>(define s (seq 3))
>(car s)
3
You can represent an infinite sequence as a function that produces one element at a time. The user (consumer) can then call the function each a new element of the sequence is needed.
An example:
(define (f x) (* x x))
(define seq
(let ()
(define n 0) ; current index
(lambda () ; the function that is to be called repeatedly
(define a (f n)) ; compute the new element
(set! n (+ n 1)) ; compute new index
a))) ; return the new element
(seq) ; compute element 0
(seq) ; compute element 1
(seq) ; ...
(seq)
(seq)
(seq)
This evaluates to:
0
1
4
9
16
25
In order to write (sequence->list s n) which computes the first n elements of the sequence s, make a loop that calls s in total n times - and collect the results in a list.
The key is to delay evaluation of the list by wrapping a procedure around it.
Here's the simplest implementation I can think of.
It's only "lazy" in the tail.
(define (seq n)
(cons n (lambda () (seq (+ n 1)))))
(define (seq-car s)
(car s))
(define (seq-cdr s)
((cdr s)))
Example use:
; Get the 'n' first elements of 's'.
(define (seq-take n s)
(if (<= n 0)
'()
(cons (seq-car s) (seq-take (- n 1) (seq-cdr s)))))
> (define s (seq 10))
> s
'(10 . #<procedure>)
> (seq-take 5 s)
'(10 11 12 13 14)
Here is another solution using delayed evaluation:
(use-modules (ice-9 receive))
(define (seq f)
(let loop ((n 0))
(lambda ()
(values (f n) (loop (1+ n))))))
(define squares (seq (lambda (x) (* x x))))
(receive (square next) (squares)
(pk square) ;; => 0
(receive (square next) (next)
(pk square) ;; => 1
(receive (square next) (next)
(pk square) ;; => 4
(receive (square next) (next)
(pk square))))) ;; => 9

Having a hard time with delete-ing every nth element in Lisp?

Trying to learn lisp, want to delete every nth. I only managed to delete the first (nth) element
(defun delete-nth (n list)
(if (zerop n)
(cdr list)
(let ((cons (nthcdr (1- n) list)))
(if cons
(setf (cdr cons) (cddr cons))
cons))))
I'd like to delete the next nth and so on
Also I tried this:
(defun remove-nth (list n)
(remove-if (constantly t) list :start n :end (+ 1 n)))
No idea how to start again
What I was thinking was concatenating, but I have no idea of how to keep track of my position.
Counting from 1 (changing to 0 is trivial):
(defun remove-every-nth (n list)
(loop for element in list
for index from 1
unless (zerop (rem index n))
collect element))
Also: Please indent your code correctly.
An alternative way to do the same thing:
(defun remove-all-nth (list period)
(remove-if
(let ((iterator 0))
(lambda (x)
(declare (ignore x))
(= 0 (mod (incf iterator) period)))) list))
(remove-all-nth '(1 2 3 4 5 6 7 8 9 0) 3)
; (1 2 4 5 7 8 0)
Perhaps a more academic recursive solution here:
(defun delete-nth (n list)
(labels ((rec (i list)
(cond ((null list) nil)
((= i 1) (rec n (cdr list)))
(t (cons (car list) (rec (1- i) (cdr list)))))))
(rec n list)))
But in real life I'd use the loop option above.