first: expects a non-empty list - scheme

I keep getting the error first: expects a non-empty list given: (make-subject (make-person 22 'm 'MW17K) (list 220 301 189 272 311)) when starting my program and just can't find out why.
;;equals 25 but my code keeps erroring. please help
(person-age (subject-person (first sub)))
(define-struct person (age sex code))
(define-struct subject (person times))
(define VP01 (make-subject (make-person 22 'm 'MW17K) (list 220 301 189 272 311)))
(define VP02 (make-subject (make-person 25 'f 'MP25G) (list 234 197 253 257 206)))
(define VP03 (make-subject (make-person 23 'f 'CT03R) (list 197 202 214 222 233)))
(define VP04 (make-subject (make-person 20 'm 'MM09R) (list 273 314 257 264 217)))
(define VP05 (make-subject (make-person 19 'm 'KR22I) (list 198 197 228 253 199)))
(define VP06 (make-subject (make-person 26 'm 'FR01B) (list 212 204 289 294 223)))
(define VP07 (make-subject (make-person 28 'f 'RA15R) (list 258 323 189 247 303)))
(define VP08 (make-subject (make-person 22 'm 'RP18R) (list 221 307 182 271 316)))
(define VP09 (make-subject (make-person 24 'f 'GH31W) (list 230 295 304 264 237)))
(define VP10 (make-subject (make-person 19 'f 'OM29Q) (list 299 194 242 303 243)))
(define subjects (list VP01 VP02 VP03 VP04 VP05 VP06 VP07 VP08 VP09 VP10))
(define (idk sub)
(cond
[(empty? sub) empty]
[(< (person-age (subject-person (first sub)))
(person-age (subject-person (first (rest sub)))))
(idk (first sub))]
[else (idk (first (rest sub)))]))
(idk subjects)

You have a type mismatch:
(define (idk sub)
(cond
[(empty? sub) empty]
[(< (person-age (subject-person (first sub))) ; here2 -------- NB
(person-age (subject-person (first (rest sub)))))
(idk (first sub))] ; here1 ------------------------ NB
[else (idk (first (rest sub)))])) ; here3
(idk subjects)
idk is called with a list of subjects, so sub inside its definition is a list of subjects. This means that (first sub) at here1 is a subject.
But then you call idk with it at here1 (or here3), and it then calls (first sub) at here2. At this point sub is a subject, not a list. Hence the error,
first: expects a non-empty list
given: (make-subject (make-person 22 'm 'MW17K) (list 220 301 189 272 311))

I think use let and car,cdr make code more clear:
(let loop ([loop_list subjects])
(if (>= (length loop_list) 2)
(if (>= (person-age (subject-person (car loop_list)))
(person-age (subject-person (cadr loop_list))))
(person-age (subject-person (car loop_list)))
(loop (cdr loop_list)))
empty))

Related

Scheme Function for Two Sublists

Write the function (split x key) that returns a list containing two sublists based on x such that all elements in the first sublist are less than or equal to key and all elements in the second sublist are greater than key.
So, for example,
(split '(40 90 80 10 60 30 20 50 70) 40)
should return
((20 30 10 40) (70 50 60 80 90))
I know a helper function with extra list parameters can simplify the problem, but I am not sure how to do it.
You can use filter:
(define (split lst num)
(list (filter (lambda (e) (>= num e)) lst)
(filter (lambda (e) (> e num)) lst)))
(split '(40 90 80 10 60 30 20 50 70) 40)
or partition:
(require racket/list)
(define (split2 lst num)
(call-with-values
(lambda ()
(partition (lambda (e) (>= num e)) lst))
list))
(split2 '(40 90 80 10 60 30 20 50 70) 40)
It is very constricted to try performing this with roll your own recursion without having a helper. You'd get lots of duplicated bad code.
Here is how to make a helper function:
(define (add-previous lst)
(define (helper previous lst)
(if (null? lst)
'()
(cons (+ previous (car lst))
(helper (car lst) (cdr lst)))))
(helper 0 lst))
This can be written easier with a named let:
(define (add-previous lst)
(let helper ((previous 0) (lst lst))
(if (null? lst)
'()
(cons (+ previous (car lst))
(helper (car lst) (cdr lst))))))
For your problem you should add two result accumulator parameters in addition to the lst. You'll typically have 2 predicates and an alternative. One for the end of the list, where you use the 2 accumulated results, one for less or equal to key where you recurse and cons the current element to the accumulator for those and the alternative where you do the same except cons to the other result accumulator.

Racket: sliding window over a vector

What are some good ways to perform a sliding window over a finite sequence in Racket, such as finding the highest sum of any sub-sequence of 4 numbers?
(define example #(3 1 4 5 10 23 1 50 0 12 40 12 43 20))
First find prefix sums:
#lang racket
(define example #(3 1 4 5 10 23 1 50 0 12 40 12 43 20))
(define-values (sums sum)
(for/fold ([sums '()] [sum 0]) ([x example])
(values (cons sum sums) (+ sum x))))
(list->vector (cons sum sums))
Result:
'#(224 204 161 149 109 97 97 47 46 23 13 8 4 3 0)
Then ... profit.
Where profit could be this:
#lang racket
(define example #(3 1 4 5 10 23 1 50 0 12 40 12 43 20))
(define (prefix-sums xs)
(define-values (sums sum)
(for/fold ([sums '()] [sum 0]) ([x xs])
(values (cons sum sums) (+ sum x))))
(list->vector (reverse (cons sum sums))))
(define (sum4 xs i)
(- (vector-ref xs (+ i 4))
(vector-ref xs i)))
(define (sum4s xs)
(for/list ([i (- (vector-length xs) 4)])
(sum4 (prefix-sums xs) i)))
(apply max (sum4s example))
For a more generic approach, here's a sequence constructor that returns a sliding window of len elements from a vector, len values at a time, which can then be used with for comprehensions:
(define (in-vector-window v len)
(make-do-sequence
(lambda ()
(values
(lambda (i) (vector->values v i (+ i len)))
add1
0
(lambda (i) (<= (+ i len) (vector-length v)))
#f
#f))))
And some example usages:
> (for/list ([(a b c d) (in-vector-window example 4)]) (list a b c d))
'((3 1 4 5) (1 4 5 10) (4 5 10 23) (5 10 23 1) (10 23 1 50) (23 1 50 0) (1 50 0 12) (50 0 12 40) (0 12 40 12) (12 40 12 43) (40 12 43 20))
> (define sums (for/list ([(a b c d) (in-vector-window example 4)]) (+ a b c d)))
> (foldl max (car sums) (cdr sums))
115

Expanded form of fold in Racket

Example from http://www.cse.unsw.edu.au/~en1000/haskell/hof.html :
(foldr / 7 (list 34 56 12 4 23))
(foldl / 7 (list 34 56 12 4 23))
Output in Racket:
5 193/196
5 193/196
What would be the full (expanded) form of foldl and foldr in this case? It is not the following:
> (/ (/ (/ (/ (/ 7 34) 56) 12) 4) 23)
1/300288
Edit: I have modified above question since implementation of fold in Racket vs Haskell has been explained in another question Why is foldl defined in a strange way in Racket?.
Edit: If I understand the answers clearly, the expanded form can be shown very clearly using "threading" module, where statements appear in order of execution (_ indicates output of previous statement):
foldl:
(require threading)
; expanded form of (foldl / 7 (list 34 56 12 4 23))
; FROM LEFT TO RIGHT:
(~> 7
(/ 34 _)
(/ 56 _)
(/ 12 _)
(/ 4 _)
(/ 23 _) )
foldr:
; expanded form of (foldr / 7 (list 34 56 12 4 23))
; FROM RIGHT TO LEFT:
(~> 7
(/ 23 _)
(/ 4 _)
(/ 12 _)
(/ 56 _)
(/ 34 _) )
The output in both cases is same:
5 193/196
5 193/196
It gives correct answers (which are different for foldl and foldr) in following example also:
; FROM LEFT TO RIGHT:
(foldl - 0 '(1 2 3 4))
(~> 0
(- 1 _) ; 1-0=1
(- 2 _) ; 2-1=1
(- 3 _) ; 3-1=2
(- 4 _)) ; 4-2=2
; FROM RIGHT TO LEFT:
(foldr - 0 '(1 2 3 4))
(~> 0
(- 4 _) ; 4-0=4
(- 3 _) ; 3-4=-1
(- 2 _) ; 2-(-1)=3
(- 1 _)) ; 1-3=-2
Output:
2
2
-2
-2
In common language, it seems:
The sent function takes 2 arguments,
the first argument is from the list, one after the other
(left to right or right to left depending on foldl and foldr),
the second argument is init first and
then the output of previous calculation.
In DrRacket, press the right mouse button on foldl and choose "Open defining file" In the provide list right click again and choose "Jump to the next bound occurance". You'll see this:
(define foldl
(case-lambda
[(f init l)
(check-fold 'foldl f init l null)
(let loop ([init init] [l l])
(if (null? l) init (loop (f (car l) init) (cdr l))))]
[(f init l . ls)
(check-fold 'foldl f init l ls)
(let loop ([init init] [ls (cons l ls)])
(if (pair? (car ls)) ; `check-fold' ensures all lists have equal length
(loop (apply f (mapadd car ls init)) (map cdr ls))
init))]))
However since you only have one list it's the first term in case lambda that is the current and the fist line checks arguments and throw exceptions. You can simplify it to:
(define (foldl f init l)
(let loop ([init init] [l l])
(if (null? l)
init
(loop (f (car l) init) (cdr l))))
Using substitution rules:
(foldl / 7 '(34 56 12 4 23)) ;==>
(loop 7 '(34 56 12 4 23)) ;==>
(loop (/ (car '(34 56 12 4 23)) 7) (cdr '(34 56 12 4 23))) ;==>
(loop (/ (car '(56 12 4 23)) (/ (car '(34 56 12 4 23)) 7)) (cdr '(56 12 4 23))) ;==>
(loop (/ (car '(12 4 23)) (/ (car '(56 12 4 23)) (/ (car '(34 56 12 4 23)) 7))) (cdr '(12 4 23))) ;==>
(loop (/ (car '(4 23)) (/ (car '(12 4 23)) (/ (car '(56 12 4 23)) (/ (car '(34 56 12 4 23)) 7)))) (cdr '(4 23))) ;==>
(loop (/ (car '(23)) (/ (car '(4 23)) (/ (car '(12 4 23)) (/ (car '(56 12 4 23)) (/ (car '(34 56 12 4 23)) 7))))) (cdr '(23))) ;==>
(/ (car '(23)) (/ (car '(4 23)) (/ (car '(12 4 23)) (/ (car '(56 12 4 23)) (/ (car '(34 56 12 4 23)) 7))))) ;==>
(/ 23 (/ 4 (/ 12 (/ 56 (/ 34 7))))) ;==>
5 193/196
I'll leave the foldr one as an exercise.
About folds and standards
The folds in #!racket are racket specific. In Scheme, more precisely #!r6rs you have fold-left and fold-right and unlike #!racket the argument order from a left to a right changes making it more similar to the *new Haskell version.
SRFI-1 list library uses the names fold and foldr and expect the same argument order for both, just like #!racket. SRFI-1 also supports different length lists and stops at the shortest one so it is the one with most features. SRFI-1 can be included in both #!racket with (require srfi/1)and with #!r6rs. (import (rnrs :1))
Haskell's foldr and foldl are not exactly equivalent to Racket's. Also, div is integer division, so you should use quotient in Racket. But even then,
(foldr quotient 7 (list 34 56 12 4 23)) => 8
(foldl quotient 7 (list 34 56 12 4 23)) => quotient: undefined for 0
You could read the documentation carefully on how foldl and foldr work, but I like to refer to the docs for the teaching languages:
(foldr f base (list x-1 ... x-n)) = (f x-1 ... (f x-n base))
(foldl f base (list x-1 ... x-n)) = (f x-n ... (f x-1 base))
So it becomes
(quotient 34 (quotient 56 (quotient 12 (quotient 4 (quotient 23 7)))))
(quotient 23 (quotient 4 (quotient 12 (quotient 56 (quotient 34 7)))))

How to define a string with values from a defined list in SCHEME

Please help me to do define a string like this..
I have a list which has the values
(define temp-list (list '398 '150 '1.15 '2875 '-900 '1565 '800 '230 '200 '0 '0 '0))
I Should declare this as..
(define b "398 150 1.15 2875 -900 1565 800 230 200 0 0 0")
How can i do this in scheme?
If you have SRFI 13 loaded, you can use string-join like so:
(define b (string-join (map number->string temp-list)))
See http://codepad.org/8DH8mCTQ:
(define temp-list (list '398 '150 '1.15 '2875 '-900 '1565 '800 '230 '200 '0 '0 '0))
(define b
(let loop ((xs temp-list) (zs '()))
(if (null? (cdr xs))
(apply string-append (reverse (cons (number->string (car xs)) zs)))
(loop (cdr xs) (cons " " (cons (number->string (car xs)) zs))))))
(write b)

How do I break a Scheme list into args to be passed to a procedure?

I want to use the predefined (max) function (R5RS) with a list of numbers, which varies in length. Unfortunately, (max) accepts input like this:
(max 2 43 5 6)
=> 43
I'm attempting to use it like so:
(define lst '(3 5 53 4 53 54 32))
(max lst)
This produces the following error.
max: expects argument of type <real number>; given (3 5 53 4 53 54 32)
How can I break this list into the individual arguments I need, as I'm passing them to (max)?
You might consider using apply (though be warned, that this may impose limits with respect to the number of elements/arguments are acceptable, depending on your implementation of Scheme):
(apply max '(3 4 2 1 78 2 1))
In general, if the number of elements is not known to be small, it might be safer to do it manually:
(define max* (list)
(if (null? list) (negative-infinity)
(let loop ((list (cdr list)) (best (car list)))
(if (null? list) best (loop (cdr list) (max best (car list)))))))
Using apply basically translates into running (max 3 4 2 1 78 2 1) but the number of arguments a procedure can be passed is not infinite on some systems. For max, you can take advantage of its commutativity by using fold:
(fold-left max -inf.0 '(3 4 2 1 78 2 1))
You can write a procedure that compares the first item to the second,
(define (largestele lst)
(if (null? (cdr lst))
(car lst)
(if (> (car lst) (cadr lst))
(largestele (cons (car lst) (cddr lst)))
(largestele (cdr lst)))))

Resources