(define-struct groceryItem( id description price))
(define grocery-master-list(list (make-groceryItem 1 "bread" 1.99)
(make-groceryItem 2 "milk" 2.99)
(make-groceryItem 3 "carrots" 3.45)
(make-groceryItem 4 "cookies" 4.55)
(make-groceryItem 5 "sauce" 3.80)
(make-groceryItem 6 "steaks" 8.25)
(make-groceryItem 7 "apples" 5.65)))
(define StructObj (make-groceryItem 1 "bread" 1.99))
(groceryItem-id StructObj)
(groceryItem-description StructObj)
(groceryItem-price StructObj)
I need to create a function called "lookup" that takes an id and a list (which initially should be the list defined above) as parameters and returns the object from the list that matches the id. need to use car and cdr functions. This is what created as the lookup function but its totally wrong...need help
(define lookup
(lambda( id grocery-master-list)
(if(null? grocery-master-list) '()
(if (= id ( groceryItem-id (car grocery-master-list))) (groceryItem-description(car grocery-master-list))
(lookup id (cdr grocery-master-list))
)
)
)
)
Below, is an example of what the call to the lookup function should look like.
(lookup 3 grocery-master-list)
This is a sort of transcript of systematically constructing the lookup function (intermediate versions are commented out with #; - in practice one would just edit them to the next version)
The design method is HtDF (How to Design Functions): one writes down stub with signature and purpose, examples, template (copied from a library of standard templates). Takes a few minutes to construct a correct solution.
(define-struct groceryItem (id description price))
(define grocery-master-list (list (make-groceryItem 1 "bread" 1.99)
(make-groceryItem 2 "milk" 2.99)
(make-groceryItem 3 "carrots" 3.45)
(make-groceryItem 4 "cookies" 4.55)
(make-groceryItem 5 "sauce" 3.80)
(make-groceryItem 6 "steaks" 8.25)
(make-groceryItem 7 "apples" 5.65)))
#| I need to create a function called "lookup" that takes an id and a list
(which initially should be the list defined above) as parameters
and returns the object from the list that matches the id.
need to use car and cdr functions. |#
(define notFoundGroceryItem (make-groceryItem 0 "" 0.0))
#; ; *stub* ;; *signature*
(define (lookup id logi) ;; GroceryItemId ListOfGroceryItem -> GroceryItem
;; produce the item from logi with given id ; *purpose statement*
notFoundGroceryItem) ; *stub body* (valid result)
; *minimal example*
(check-expect (lookup 1 empty) notFoundGroceryItem ) ; (passes with above stub)
(define (fn lox) ;; ListOfX -> Y ; *template*
;; produce a Y from lox using natural recursion ;
(cond ;
[(empty? lox) ... ] ; ... = "base case value" ;; Y
[else (.... ; .... = "inventory fn(s)" ;; X Y -> Y
(first lox) (fn (rest lox))) ])) ;
; groceryItem-id ;; GroceryItem -> GroceryItemId ; *inventory*
; = ;; GroceryItemId GroceryItemId -> Boolean ;
; car ;; ListOfGroceryItem -> GroceryItem ;
; cdr ;; ListOfGroceryItem -> ListOfGroceryItem ;
; (substituting in template)
#;(define (lookup id logi) ;; GroceryItemId ListOfGroceryItem -> GroceryItem
;; produce the item from logi with given id
(cond
[(empty? logi) ... id ] ;; GroceryItem
[else (....
id
(car logi) ;; GroceryItem
(lookup id (cdr logi)) ;; GroceryItem
) ]))
; (use first check-expect to replace ...)
#;(define (lookup id logi) ;; GroceryItemId ListOfGroceryItem -> GroceryItem
;; produce the item from logi with given id
(cond ; (first example still passes with this version)
[(empty? logi) notFoundGroceryItem ] ;; GroceryItem
[else (....
id
(car logi)
(lookup id (cdr logi))
) ]))
(define grocery-test-list (list (make-groceryItem 1 "bread" 1.99)))
(check-expect (lookup 1 grocery-test-list) (make-groceryItem 1 "bread" 1.99) )
(check-expect (lookup 99 grocery-test-list) notFoundGroceryItem )
; (use above to deduce ....)
(define (lookup id logi) ;; GroceryItemId ListOfGroceryItem -> GroceryItem
;; produce the item from logi with given id
(cond
[(empty? logi) notFoundGroceryItem ]
[else (if (= id (groceryItem-id (car logi)))
(car logi)
(lookup id (cdr logi))) ]))
(check-expect (lookup 3 grocery-master-list) (make-groceryItem 3 "carrots" 3.45))
Welcome to DrRacket, version 8.4 [cs].
Language: Beginning Student.
All 4 tests passed!
>
Related
Related to this question: Pair combinations in scheme, I'm trying to write a function that creates possible sequences of a list. I'm also trying to annotate it to myself with some lets, rather than putting everything in maps. Here is what I have so far:
(define (remove-from-list elem L)
(filter (lambda (x) (not (= x elem))) L))
(define (prepend-element-to-list-of-lists elem L)
(map (lambda (x) (append (list elem) x)) L))
(define (perm L)
; returns a list of lists, so base case will be '(()) rather than '()
(if (null? L) '(())
; we will take out the first element, this is our "prepend-item"
(let ((prepend-element (car L))
(list-minus-self (remove-from-list (car L) L)))
; prepend-to-list-of-lists
(let ((other-lists-minus-self (perm list-minus-self)))
(prepend-element-to-list-of-lists prepend-element other-lists-minus-self)
))))
(perm3 '(1 2 3))
((1 2 3)) ; seems to be stopping before doing the recursive cases/iterations.
What I'm trying to do here is to take out the first element of a list, and prepend that to all list-of-lists that would be created by the procedure without that element. For example, for [1,2,3] the first case would be:
Take out 1 --> prepended to combinations from [2,3], and so eventually it comes to [1,2,3] and [1,3,2].
However, I was seeing if I can do this without map and just calling itself. Is there a way to do that, or is map the only way to do the above for 1, then 2, then 3, ...
And related to this, for the "working normal case", why does the following keep nesting parentheticals?
(define (perm L)
(if (null? L) '(())
; (apply append <-- why is this part required?
(map (lambda (elem)
(map (lambda (other_list) (cons elem other_list))
(perm (remove-from-list elem L))))
L)))
; )
That is, without doing an (apply append) outside the map, I get the "correct" answer, but with tons of nested parens: (((1 (2 (3))) (1 (3 (2)))) ((2 (1 (3))) (2 (3 (1)))) ((3 (1 (2))) (3 (2 (1))))). I suppose if someone could just show an example of a more basic setup where a map 'telescopes' without the big function that might be helpful.
Regarding "where do parens come from", it's about types: the function being mapped turns "element" into a "list of elements", so if you map it over a list of elements, you turn each element in the list into a list of elements: ....
[ 1, 2, 3, ] -->
[ [ 1a, 1b ], [2a], [] ]
, say, (in general; not with those functions in question). And since there's recursion there, we then have something like
[ [ [1a1], [] ], [[]], [] ]
, and so on.
So map foo is listof elts -> listof (listof elts):
`foo` is: elt -> (listof elts)
-------------------------------------------------------
`map foo` is: listof elts -> listof (listof elts)
But if we apply append after the map on each step, we've leveled it into the listof elts -> listof elts,
`map foo`: listof elts -> listof (listof elts)
`apply append`: listof (listof elts) -> listof elts
----------------------------------------------------------------------
`flatmap foo`: listof elts -> listof elts
and so no new parens are popping up -- since they are leveled at each step when they appear, so they don't accumulate like that; the level of nestedness stays the same.
That's what apply append does: it removes the inner parens:
(apply append [ [x, ...], [y, ...], [z, ...] ] ) ==
( append [x, ...] [y, ...] [z, ...] ) ==
[ x, ..., y, ..., z, ... ]
So, as an example,
> (define (func x) (if (= 0 (remainder x 3)) '()
(if (= 0 (remainder x 2)) (list (+ x 1))
(list (+ x 1) (+ x 2)))))
> (display (map func (list 1 2 3 4)))
((2 3) (3) () (5))
> (display (map (lambda (xs) (map func xs)) (map func (list 1 2 3 4))))
(((3) ()) (()) () ((6 7)))
> (display (flatmap func (list 1 2 3 4)))
(2 3 3 5)
> (display (flatmap func (flatmap func (list 1 2 3 4))))
(3 6 7)
Now that the types fit, the flatmap funcs compose nicely, unlike without the flattening. Same happens during recursion in that function. The deeper levels of recursion work on the deeper levels of the result list. And without the flattening this creates more nestedness.
For a school project I have to think about my own encryption method and have to create a program in scheme, which can encrypt and decrypt with that method. I'm quite new to scheme so I need a bit of help.
So I'm working with recursion as you see in my code and as you can see I'm converting the letters into numbers and then I'm moving the letters up as many times as stated in the key. After that I want to convert them back into letters. So my problem is that I want to start with the the key again from the beginning when it's empty, but I don't really know how to do it.
If you want to help me even more, I want to declare a second key, which consists of numbers. That key decides when the first key starts from the beginning again.
I hope you can help me!
(define (codieren str ausgabe key1)
(verschluesseln (umwandeln (string->list str) ausgabe) key1 '()))
(define (umwandeln liste ausgabe)
(cond
[(null? liste) ausgabe]
[else (umwandeln (rest liste)
(append ausgabe (list (char->integer (first liste)))))]))
(define (verschluesseln zahlenListe key1 ausgabe)
(cond
[(null? zahlenListe) ausgabe]
[else (verschluesseln (rest zahlenListe) (rest key1)
(append ausgabe (list (+ (first zahlenListe) (first key1)))))]))
I have renamed some variables :)
Legend
------
ausgabe = output
codieren = encode
verschluesseln = encrypt
umwandeln = convert
zahlenListe = numlist
... and added some signatures and purpose statements. check-expects are tests in Racket's BSL (Beginning Student Language).
;; String [Listof Character] [Listof Number] -> [Listof Number]
;; converts, then encrypts str by key1
(define (encode str output key1)
(encrypt (convert (string->list str) output) key1 '()))
(check-expect (encode "abc" '() (list 1 1 1)) (list 98 99 100))
;; [Listof Character] [Listof Character] -> [Listof Character]
;; converts each character in liste to an integer
(define (convert liste output)
(cond
[(null? liste) output]
[else (convert (rest liste)
(append output (list (char->integer (first liste)))))]))
;; [Listof Number] [Listof Number] [Listof Number] -> [Listof Number]
;; increments each number in numlist by key1
(define (encrypt numlist key1 output)
(cond
[(null? numlist) output]
[else (encrypt (rest numlist)
(rest key1)
(append output (list (+ (first numlist) (first key1)))))]))
You can build analogous decoder functions (that work backwards):
;; [Listof Number] [Listof Number] [Listof Number] -> String
(define (decode code output key1)
(list->string (convert-back (decrypt code key1 output) '())))
(check-expect (decode (list 98 99 100) '() (list 1 1 1)) "abc")
;; [Listof Number][Listof Number] [Listof Number] -> [Listof Number]
(define (decrypt numlist key1 output)
(cond
[(null? numlist) output]
[else (decrypt (rest numlist)
(rest key1)
(append output (list (- (first numlist) (first key1)))))]))
(check-expect (decrypt (list 98 99 100) (list 1 1 1) '()) (list 97 98 99))
;; [Listof Number] [Listof Character] -> [Listof Character]
(define (convert-back liste output)
(cond
[(null? liste) output]
[else (convert-back (rest liste)
(append output (list (integer->char (first liste)))))]))
(check-expect (convert-back (list 97 98 99) '()) (list #\a #\b #\c))
And then test if encoding and decoding something by a key returns the same thing:
;; String [Listof Number] -> String
;; encodes and decodes a str by key
(define (encode-decode-identity str key)
(decode (encode str '() key) '() key))
(check-expect (encode-decode-identity "abc" (list 1 1 1)) "abc")
(check-expect (encode-decode-identity "Gödel" (list 3 0 1 -9 7)) "Gödel")
See how key was just used in two two functions.
Note that our encoded message has been a [Listof Number]. This can be converted to a string:
;; [Listof Number] String -> String
;; converts an encoding `code` to its string form
(define (code-to-string code output)
(cond [(null? code) output]
[else (code-to-string (rest code)
(string-append output (int->string (first code))))]))
(check-expect (code-to-string (list 98 99 100) "") "bcd")
(check-expect (code-to-string (encode "Church" '() (list 4 2 3 -5 0 9)) "") "Gjxmcq")
... which can then be used to encode something multiple times (as you asked):
;; Number String [Listof Number] -> String
;; encodes str n times using key
(define (encode-n-times n str key)
(cond [(= n 0) str]
[else (encode-n-times (- n 1) (code-to-string (encode str '() key) "") key)]))
(check-expect (encode-n-times 3 "abc" (list 1 1 1)) "def")
Instead of "key starts from the beginning again," multiple applications of encode are composed.
Im trying to modify vowel code I found on SOF, Posted below , im trying to make it into a word list instead so I can check if the word is in the list or not. But I keep getting errors:
;; A list of words
(define words-list (cons #\dog (cons #\pig )
;; split-string : string -> (listof string-pieces)
;; converts a string into a list of string pieces.
(define (split-string a-string)
(string->list a-string))
;; has-word? : string-piece -> boolealn
;; checks whether a string-piece is a vowel
(define (has-word? string-piece words)
(cond ((empty? words) false)
((equal? string-piece (first words)) true)
(else (has-word? string-piece (rest words)))))
;; Test
(check-expect (has-word? #\i word-list) true)
(check-expect (has-word? #\x word-list) false)
;; contains-words-list : (listof string-pieces) -> boolean
;; determines whether any items on a list of string-pieces
;; contains a piece that represents a word, from a list of words.
(define (contains-words-list losp)
(cond ((empty? losp) false)
((false? (has-word? (first losp) words-list))
(contains-words-list (rest losp)))
(else (has-word? (first losp) words-list))))
;; Test
(check-expect (contains-word-list (cons #\h (cons #\i empty))) true)
(check-expect (contains-word-list (cons #\h (cons #\h empty))) false)
;; contains-word? : string -> boolean
;; checks whether a string contains a vowel.
(define (contains-word? a-string)
(contains-word-list (split-string a-string)))
;; Test
(check-expect (contains-word? "pig") true)
I keep getting errors such as the cons for dog and pig being too big, and it wont produce the right output, any guidance would be great
;; A list of words
(define words-list (cons "dog" (cons "pig" '())))
;; split-string : string -> (listof string-pieces)
;; converts a string into a list of string pieces.
(define (split-string a-string)
(string->list a-string))
;; has-word? : string-piece -> boolealn
;; checks whether a string-piece is a vowel
(define (has-word? string-piece words)
(cond ((null? words) #f)
((equal? string-piece (car words)) #t)
(else (has-word? string-piece (cdr words)))))
;; contains-words-list : (listof string-pieces) -> boolean
;; determines whether any items on a list of string-pieces
;; contains a piece that represents a word, from a list of words.
(define (contains-words-list losp)
(cond ((null? losp) #f)
((false? (has-word? (car losp) words-list))
(contains-words-list (cdr losp)))
(else (has-word? (car losp) words-list))))
;; contains-word? : string -> boolean
;; checks whether a string contains a vowel.
(define (contains-word? a-string)
(contains-word-list (split-string a-string)))
Your syntax for creating a list of strings is wrong:
> (cons #\dog (cons #\pig ))
Unhandled exception
Condition components:
1. &lexical
2. &message: "invalid syntax"
3. &irritants: (#\d #\o)
4. &source-position:
file-name: *stdin*
character: 10
and you are missing parens. Try
(list "dog" "pig")
for your word-list. Your check-expect forms are wrong as well, for similar reasons.
;; An association list (al) is either
;; empty or
;; (cons (list k v) alst), where
;; k is a nat (the key),
;; v is a string (the value), and
;; alst is an association list (al)
updatestring takes an association list, a number (findnum) and a string (newstring) and if there is a number the same as findnum in the association list, then it replaces the string in the list with newstring.
(check-expect(updatestring empty 3 "hi") (list (list 3 "hi")))
(check-expect(updatestring (list (list 1 "hi")(list 5 "wow")) 5 "new")(list (list 1 "hi")(list 5 "new")))
(check-expect(updatestring (list (list 1 "hi")(list 5 "wow")) 2 "nice")(list (list 2 "nice") (list 1 "hi")(list 5 "wow")))
I'm having trouble with the code as this is what I have.
(define (al-update alst akey avalue)
(cond
[(empty? alst) (list (list akey avalue))]
[(= (first(first alst)) akey) (al-update (rest alst) akey avalue)]
[else (list(list akey avalue alst))]))
The problem is that my code returns
(list (list 5 "new" (list (list 1 "hi") (list 5 "wow"))) instead of (list (list 1 "hi") (list 5 "new"))
and
(list(list 2 "nice" (list (list 1 "hi") (list 5 "wow")))) instead of (list (list 2 "nice") (list 1 "hi")(list 5 "wow")))
Any tips and answers would be very much appreciated thanks!
Your recursive structure needs to be something like this:
(define (al-update alist akey avalue)
(if (empty? alist) ; base, end recusion
'()
(cons (let ((key+value (first alist))) ; element, one-by-one
(if (= ...)
...
...))
(al-update (rest alist) akey avalue)))) ; recursion
In your code there are a number of problems. The else clause needs to recurse over the rest of the list. In the = clause you need to do the substitution and recurse. In my code above, I combined the two clauses that recurse.
It says "if there is a number the same as findnum in the association list, then it replaces the string in the list with newstring", but in your example if the given number does not exist you add that into the list.
(check-expect (updatestring (list (list 1 "hi") (list 5 "wow")) 2 "nice")
(list (list 2 "nice") (list 1 "hi") (list 5 "wow")))
(check-expect(updatestring empty 3 "hi") (list (list 3 "hi")))
Code and the examples (tests) should be these:
(define (al-update alst akey avalue)
(cond
[(empty? alst) empty]
[(= (first (first alst)) akey) (cons (list (first (first alst)) avalue)
(al-update (rest alst) akey avalue))]
[else (cons (first alst) (al-update (rest alst) akey avalue))]))
(check-expect (updatestring empty 3 "hi") empty)
(check-expect (updatestring (list (list 1 "hi") (list 5 "wow")) 5 "new")
(list (list 1 "hi") (list 5 "new")))
(check-expect (updatestring (list (list 1 "hi") (list 5 "wow")) 2 "nice")
(list (list 1 "hi") (list 5 "wow")))
(check-expect (updatestring (list (list 1 "hi") (list 5 "wow") (list 2 "bad")) 2 "nice")
(list (list 1 "hi") (list 5 "wow") (list 2 "nice")))
By the way "car" is equivalent to "first" and "cdr" is "rest".
I have the following code and its evaluation as comment:
(require scheme/mpair)
(list) ;; '()
(mlist) ;; '()
(cons 'un (list)) ;; '(un)
(list 'un (list)) ;; '(un ())
(mcons 'un (mlist)) ;; (mcons 'un '())
(mlist 'un (mlist)) ;; (mcons 'un (mcons '() '()))
My questions:
why doesn't the 3rd expression return '(), instead of '(un . ())?
why don't the 5th expression and the the 6th expression return the same thing?
As a general example, (list x y z) is an abbreviation for (cons x (cons y (cons z empty))). And (list) is an empty list, i.e. empty. So (list 'un (list)) is just an abbreviation for (cons 'un (cons empty empty)) - I.e. a list with two elements in it: the symbol 'un and an empty list. mlist similarly is an abbreviation for a sequence of mcons'es onto empty at the very end.