scheme structures and lists - list

(define-struct position (name numshares share-price))
(define p1
(cons (make-position "INT" 10 192) (cons (make-position "SSS" 4 42)
empty)))
mult is my helper function
(define (mult n)
( * (position-numshares n)
(position-share-price n)))
const takes the position-numshares and the position-share-price in a list and multiplies them together.
(define (const n)
(cond
[(empty? n) empty]
[(cons? n)
(+ (mult (first n))
)]))
What I would like to do is take the first of the list and add the rest of the list together. Instead, I only get the first of the list. So if I do (const p1) I only get 1920, but I would like to get 2088 (10*192 + 4*42). I've tried recurring for the rest, but get an error. I am probably missing something simple. Help would be appreciated.

First, note that in general, you can do
(list a b)
instead of
(cons a (cons b empty))
so you define p1 with
(define p1
(list (make-position "INT" 10 192)
(make-position "SSS" 4 42)))
which is easier to read, and makes your intent clearer. Now, to get 1920 from a structure created by (make-position "INT" 10 192), you've defined your helper procedure mult. You can map mult over your list p1 to get a new list of the products, i.e., (1920 168). Then you can use foldl with + and 0 on that list to compute its sum.
(define (const lst)
(foldl + 0 (map mult lst)))
(const p1)
;=> 2088
If you don't want to use fold and map (which might be reasonable, since map means that a new list is getting allocated), you can write this out manually:
(define (const lst)
(let const ((sum 0) (lst lst)) ; pretty much an implementation of fold, but
(if (null? lst) ; with the function + built in, and mult applied
sum ; to each element before passing to +
(const (+ sum (mult (car lst)))
(cdr lst)))))
(const p1)
;=> 2088
Another alternative would be to use foldl, but instead of passing +, pass in a function that combines + and mult:
(define (const3 lst)
(foldl (lambda (struct sum)
(+ (mult struct) sum))
0
lst))
(const3 p1)
As a Common Lisper, it's a bit disappointing to me that Scheme's foldl procedure doesn't take a key argument that gets applied to each element of the list before the function is applied to it. In Common Lisp, we'd write (foldl/foldr are reduce in Common Lisp):
(reduce '+ p1 :key 'mult)

Related

How to transform a list into a set in LISP?

I have been trying to transform a linear list into a set but with no avail. Everytime I run this, I get some weird compilation errors like "badly formed lambda" which points to the way I use append. Here is my code:
(defun mem(e l)
(cond
((null l) nil)
((equal e (car l)) t)
((listp (car l)) (mem e (car l)))
(t(mem e (cdr l)))
)
)
(defun st(l k)
(cond
((null l) nil)
(( mem '(car l) 'k) (st (cdr l) k))
((listp (car l)) (st (car l) k))
( t (st (cdr l) (append((car l) k)) ))
(t(mem e (cdr l)))
)
)
EDIT: frankly I just want to remove the duplicates from list l
Prefer Standard Library Functions
EDIT: frankly I just want to remove the duplicates from list l
Common Lisp has a remove-duplicates function. The documentation inclues examples:
Examples:
(remove-duplicates "aBcDAbCd" :test #'char-equal :from-end t) => "aBcD"
(remove-duplicates '(a b c b d d e)) => (A C B D E)
(remove-duplicates '(a b c b d d e) :from-end t) => (A B C D E)
(remove-duplicates '((foo #\a) (bar #\%) (baz #\A))
:test #'char-equal :key #'cadr) => ((BAR #\%) (BAZ #\A))
(remove-duplicates '((foo #\a) (bar #\%) (baz #\A))
:test #'char-equal :key #'cadr :from-end t) => ((FOO #\a) (BAR #\%))
Are you trying to flatten the list too?
From your code for mem, where you do:
((listp (car l)) (mem e (car l)))
it looks like you want your member function to also recurse into sublists. That's a bit questionable, even when working with sets, since sets can traditionally include other sets. E.g., {{3},{4},5} is a set containing 5, the set {3}, and the set {4}. It's not the same as the set {3,4,5}. Your st function also looks like it's trying to recurse into lists, which makes it seem like you want to flatten you lists, too. Again, that's a bit questionable, but if you want to do that, then your conversion to a set would be easier as a "flatten, then remove duplicates" process:
(defun flatten (list)
"Returns a fresh list containing the leaf elements of LIST."
(if (listp list)
(mapcan 'flatten list)
(list list)))
;; CL-USER> (flatten '(1 2 (3 4) 5 ((6))))
;; (1 2 3 4 5 6)
(defun to-set (list)
"Returns a set based on the elements of LIST. The result
is a flat list containing the leaf elements of LIST, but
with any duplicate elements removed."
(delete-duplicates (flatten list)))
;; CL-USER> (to-set '(1 3 (3 4) ((4) 5)))
;; (1 3 4 5)
Notes
I get some weird compilation errors like "badly formed lambda" which points to the way I use append.
Yes, you're trying to call append like: (append((car l) k)). That's actually not a problem for append. Remember, the syntax for a function call in Lisp is (function argument…). That means that you've got:
(append ((car l) k))
<function> <argument1>
But your argument1 is also a function call:
((car l) k )
<function> <argument1>
In Common Lisp, you can't use (car l) as a function. The only thing that can appear for a function is a symbol (e.g., car, append) or a lambda expression (e.g., (lambda (x) (+ x 1)).
You want to call (append (car l) k) instead.
First, CL does not have a set data type.
Lists, however, can be used as sets, you do not need to write any special code for that.
Second, I don't understand what your st function is supposed to do, but I bet that in the second cond clause you should not quote (car l) and k. You should use meaningful names for your functions and avoid abbreviations. As per your explanation in the comment, you should use pushnew instead.
Third, your mem function is quite weird, I am pretty sure you do not mean what you wrote: e is searched along a path in the tree l, not in the list l. As per your explanation in the comment, you should check both car and cdr:
(defun tree-member (tree element &key (test #'eql))
(if (consp tree)
(or (tree-member (car tree) element :test test)
(tree-member (cdr tree) element :test test))
(funcall test element tree)))

Abstract List Functions in Racket/Scheme - Num of element occurrences in list

So I'm currently stuck on a "simple?" function in Racket. It's using the Intermediate Student with lambda language.
Some restrictions on this are that NO recursion is allowed, neither are local functions. It's plain and simple abstract list functions.
What this function is supposed to do is to take in a list of numbers, and output a list of pairs in which each pair has the first element as the number with the second element being the number it has occurred in the list.
Examples:
(1 1 2 3) => ((1 2) (2 1) (3 1))
(2 3 4 3) => ((2 1) (3 2) (4 1))
I have a function that produces the number of occurrences by inputting a list of numbers and a number which is:
(define (occurrences lon n)
(length (filter (lambda (x) (= x n)) lon)))
My approach, which was clearly wrong was:
(define (num-pairs-occurrences lon)
(list (lambda (x) (map (occurrences lon x) (remove x lon)) x))
I thought the above would work, but apparently my lambda isn't placed properly. Any ideas?
It's a bit trickier than you imagine. As you've probably noticed, we must remove duplicate elements in the output list. For this, is better that we define a remove-duplicates helper function (also using abstract list functions) - in fact, this is so common that is a built-in function in Racket, but not available in your current language settings:
(define (remove-duplicates lst)
(foldr (lambda (e acc)
(if (member e acc)
acc
(cons e acc)))
'()
lst))
Now it's easy to compose the solution using abstract list functions:
(define (num-pairs-occurrences lon)
(map (lambda (e) (list e (occurrences lon e)))
(remove-duplicates lon)))
The above might return and output list in a different order, but that's all right. And before you ask: yes, we do need that helper function. Please don't ask for a solution without it...
An easy, self-contained solution would be:
(define (num-pairs-occurences lst)
(foldl (lambda (e r)
(if (or (null? r) (not (= (caar r) e)))
(cons (list e 1) r)
(cons (list e (add1 (cadar r))) (cdr r))))
null
(sort lst >)))
Basically, you sort the list first, and then you fold over it. If the element (e) you get is the same as the first element of the result list (r), you increment the count, otherwise you add a new sublist to r.
If you sort by > (descending), you can actually use foldl which is more memory-efficient. If you sort by < (ascending), you need to use foldr which is less efficient.

How do I handle a variable number of arguments passed to a function in Racket?

I like creating functions which take an unlimited number of arguments, and being able to deal with them as a list. It's been useful to me when creating binary trees & I'm using it for a variation on the nearest-neighbor algorithm right now. My method, however, is really horrible: since I can't think of a way to iterate over an improper list (which may well be improper & degenerate), I tried using various list functions to force the improper list into list form.
This is my best attempt in a simple function to determine difference between map-nodes (works, just not sure why it works):
(define distance-between
(lambda xs
(let ([input-list (list* xs null)])
(letrec
([f (lambda (xs acc)
(if (null? (cdr xs))
acc
(f (cdr xs)
(+ (abs (- (map-node-x (car xs))
(map-node-x (cadr xs))))
(abs (- (map-node-y (car xs))
(map-node-y (cadr xs))))
acc))))])
(f (car input-list) 0)))))
As you can see, it's an ugly solution and involves some of what seems like magic to me - why is the improper list coerced into list form when I include it in a list*? (note: this sentence is misleading, this does not occur).
I'd rather have a pretty solution and no magic. Can anyone help?
For example a typical input would be:
(distance-between (map-node 1 2) (map-node 2 3) (map-node 3 4))
with the expected result:
4
(a distance of 2 between map-node (a) and m-n (b), plus a distance of 2 between map-node (b) and map-node (c)).
Alternatively one might simply input:
(distance-between (map-node 1 2) (map-node 2 2))
and get an answer of:
1
If I attempted this on the raw input, without my (let ([input-list...])...) statement, it would cause an error as (? not actually sure why given response to this question).
The function works as expected.
There's nothing improper about the list received as a variadic argument list (meaning: variable number of arguments). For example:
(define test-list
(lambda xs
(length xs))) ; xs is a normal list, use it like any other list
(test-list 1 2 3 4)
=> 4
In the above example, the xs parameter is a normal, plain, vanilla list, there's nothing improper about it. You can iterate over it as you would over any other list. There's no need to car it, it's already a list! Also, notice that the same function can be written like this:
(define (test-list . xs)
(length xs)) ; xs is a normal list, use it like any other list
Just for reference: an improper list is one that does not end with the null list. For example: '(1 2 3 . 4). Again, that's not how a variadic argument list looks.
I also don't understand how your variadic argument list could be improper.
But to answer your original question (how to iterate over a possibly improper list, somewhat more elegantly), here is one way using match:
#lang racket
(define (properly-sum-improper-list xs)
(let loop ([acc 0]
[xs xs])
(match xs
[(list) acc]
[(cons x more) (loop (+ acc x) more)]
[x (+ acc x)]))) ;last item of improper list
(require rackunit)
(check-equal? (properly-sum-improper-list '(1 2 3 4)) 10)
(check-equal? (properly-sum-improper-list '(1 2 3 . 4)) 10)
However needing to do this, at all, is probably an indication you want to fix or change something else.
Your list is not improper. When your argument is not a pair, like (lambda xs body ...) or (define (fun . xs) body ...) all your arguments gets slurped into a list. Eg.. (fun 1 2 3) would make xs '(1 2 3). Doing (list* '(1 2 3) '()) makes '((1 2 3) which you undo right away by calling your loop with car which makes it '(1 2 3) again.
Other than that your procedure works as intended. You might clean up your procedure a little, but since there is no list comprehensions that glides over a list folding over the two next elements it won't become much smaller. Below is basically the same code, but abstracting out the procedure that does the work (which if existed a foldl-pair you could have used) and with a named let as a iterator loop (which is syntactic sugar for a letrec+call).
(define (distance-between e1 . lst)
(define (add-diff-acc e1 e2 acc)
(+ (abs (- (map-node-x e1) (map-node-x e2)))
(abs (- (map-node-y e1) (map-node-y e2)))
acc))
(let iterate ((e1 e1) (lst lst) (acc 0))
(if (pair? lst)
(let ((e2 (car lst)))
(iterate e2 (cdr lst) (add-diff-acc e1 e2 acc)))
acc)))
EDIT: About syntax sugar, named let and letrec.
(let ((x 10) (y 19))
body)
is syntactic sugar for a anonymous procedure call
((lambda (x y)
body)
10 19)
A named let is just giving that procedure a name, though as if by letrec, making a recursive binding. you call it with the name you give and the arguments will be what you supply instead of the initial value in the let. I'm used to them and prefer them today. It might take some time to get used to though.
Most of the code we write is syntactic sugar for some lower level stuff. The macros are nested so that your letrec form could get reduced down lambdas eventually. The whole procedure without syntactic sugar would look like this:
(define distance-between
(lambda (e1 . lst)
((lambda (add-diff-acc)
((lambda (iterate e1 lst acc) ; emulate Y to substitute `letrec`
(iterate iterate e1 lst acc))
(lambda (iterate e1 lst acc)
(if (pair? lst)
((lambda (e2)
(iterate iterate e2 (cdr lst) (add-diff-acc e1 e2 acc)))
(car lst))
acc))
e1 lst 0))
(lambda (e1 e2 acc)
(+ (abs (- (map-node-x e1) (map-node-x e2)))
(abs (- (map-node-y e1) (map-node-y e2)))
acc)))))

How to make a copy of a procedure in Scheme?

So, from the SICP we know that the cons car and cdr can be defined as a procedure:
(define (cons x y)
(lambda (m) (m x y)))
(define (car z)
(z (lambda (p q) p)))
(define (cdr z)
(z (lambda (p q) q)))
But the pre-defined procedure list, which takes the arguments to build a list, uses the original cons. That means, a list that list built, isn't a procedure as I want.
(car (list 1 2 3))
;The Object (1 2 3) is not applicable
So i write this:
(define (list . l)
(if (null? l)
'()
(cons (original-car l)
(list (original-cdr l)))))
I just wondering how to define the original-car and original-cdr. Are there some way to make a copy of a procedure in Scheme? Or there's some alternate way to solve this problem. thx
If you need to save a reference to the "original" procedures before redefining them, simply create an alias before defining the "new" procedures (I guess that's what you mean by "copying" them). Like this:
(define original-cons cons)
(define original-car car)
(define original-cdr cdr)
(define original-list list)
In this way, the old procedures can still be used, as long as we refer to them by their new names. In other words, the implementation of cons, car, cdr and list as procedures will look like this:
(define (my-cons x y)
(lambda (m) (m x y)))
(define (my-car z)
(z (lambda (p q) p)))
(define (my-cdr z)
(z (lambda (p q) q)))
(define (my-list . els)
(if (null? els)
'()
(my-cons
(original-car els)
(apply my-list (original-cdr els)))))
And sure enough, it works:
(define lst (my-list 1 2 3 4))
lst
=> #<procedure>
(my-car lst)
=> 1
(my-car (my-cdr lst))
=> 2
List in an implementation is defined as
(define (list . l) l)
However, this is using a lot of the underlying implementation. E.g. to work it uses the native cons. cons as defined in SICP is a thought experiment so you're implementation needs a little correction:
(define (my-cons x y)
(lambda (m) (m x y)))
(define (my-car z)
(z (lambda (p q) p)))
(define (my-cdr z)
(z (lambda (p q) q)))
(define (my-list . l)
(define (my-list-aux l)
(if (null? l)
'()
(my-cons (car l)
(my-list-aux (cdr l)))))
(my-list-aux l))
;; optional, update binding
(define car my-car)
(define cdr my-cdr)
(define list my-list)
my-cons my-car, my-cdr and my-list are as defined in your question. Only change is reference to correct procedure (with name not conflicting with Scheme)

Scheme, how to square just negative numbers in a list leaving the rest of the list intact

I have been working on a call to accumulate which goes as follows:
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
However when I try to square something by slecting it through filter the answer doesn't work. What I have so far is this:
(define (f2b items)
(accumulate (lambda (x y)
(cons (append
(map square (filter negative? (filter number? x))) x) y)) () items)
)
The Input I give is:
(f2a '(("sdas" 89) (-53 "sad")))
The output I get is:
((sdas 89) (2809 -53 sad))
I can't seem to get the negative number to go away.
It would be much easier to use filter and map. Filter is predefined but it looks like this.
(define (filter1 predicate sequence)
(cond
((null? sequence) null)
((predicate (car sequence))
(cons (car sequence)
(filter predicate (cdr sequence))))
(else (filter predicate (cdr sequence)))))
map is also predefined, it just runs a function over a list.
This should be pretty simple to write, but incase you need help you should just write a lamdba for the predicate in filter.
Actually, the functionality you describe is not usually the job of an accumulator. Instead, squaring negative numbers in a list seems like the perfect job for something like a map.
First, let's do:
(define (make-positive x)
(if (and (number? x) (negative? x))
(square x)
x))
Now suppose we want to operate on a list called lst. If it was just a flat list, like '(1 "2" -5 -4 6), then we could just
(map make-positive lst)
Since we need to operate on lists which are nested two levels deep, we could do:
(map (lambda (x)
(map make-positive x))
lst)
If we wanted to operate on lists which are nested arbitrarily deep, we could do:
(define (nested-map fn elm)
(if (list? elm)
(map (lambda (x) (nested-map fn x)) elm)
(fn elm)))
(nested-map make-positive lst)
PS - we can define map like this:
(define (map fn lst)
(if (empty? lst)
'()
(cons (fn (car lst))
(map fn (cdr lst)))))