Scheme function using association lists and Mapping - dictionary

I'm trying to create a function in scheme that's called allAssociation. It takes in 2 parameters, a list of symbols and an assoc-list. Calling this function should return a list of data with elements that correspond to the keys of the assoc-list.
Here is an example:
Input:
(allAssociation '(a c d) '((a allen)(b bob)(c (carl cooper))(d doug)))
Output:
(allen (carl cooper) doug).
I am trying to use map and lambda to implement this function, but I am a little stumped.
Currently I have this snippet of code:
(define AllAssociation
(lambda (key alist)
(if (null? alist)
'()
[insert rest of logic]
)))
But I am struggling with implementing the logic of using map to match up each of the elements of the key with the association list. Any help would be much appreciated, for I am very new to scheme. Thank you.

Basically you iterate over the keys list, and use assoc to retrieve the first matching element in list lst.
If you need to use map (as your text suggests), then something like this will do:
(define all-association
(lambda (keys lst)
(map (lambda (key) (cadr (assoc key lst)))
keys)))
If you have to do it without map (as your code suggests), the equivalent would be:
(define all-association
(lambda (keys lst)
(if (null? keys)
'()
(cons (cadr (assoc (car keys) lst))
(all-association (cdr keys) lst)))))
Testing:
> (all-association '(a c d) '((a allen)(b bob)(c (carl cooper))(d doug)))
'(allen (carl cooper) doug)

Related

I'm trying to understand this piece of Scheme code, can someone explain it to me?

I found this Scheme code on the internet, it outputs all subsets given a list, can someone explain how it works?
(define (subsets s) (if (null? s)
(list ())
(let ((rest (subsets (cdr s))))(append rest (map (lambda (x) (cons (car s) x)) rest)))))
(subsets '(a b c))
You really need to format it:
(define (subsets s)
(if (null? s)
(list ())
(let ((rest (subsets (cdr s))))
(append rest
(map (lambda (x)
(cons (car s) x))
rest)))))
What it does is return (()) for the argument '()
For a one element argument eg. '(b) if binds rest to the subsets of every element execept the first.. Which is no elements so rest is (()) and then it returns a list consisting of all the elements in rest as well as each list element of rest with b added to front. Thus (() (b)).
For a two element argument eg. '(a b) it binds rest to the subsets of every element except the first. Which is (b) so we know from above that it is (() (b)) and we know it will use those as well as every element with a added to the beginning: (() (b) (a) (a b))
I could go on but I'm guessing you get the picture?

Scheme/Racket: most idiomatic way to append single element to end of list

I want to append the element b to the list a (let's say (a1, a2, ... an)), e.g. appending the number 3 to (1 2) gives (1 2 3)
So far I've been doing
(append a (list b)), which is kind of long and inelegant, so I wonder if there's a "better" way...
Are you building a list piecemeal, an item at a time? If so, the idiomatic way to do this is to build the list backward, using cons, and then reversing the final result:
(define (map-using-cons-and-reverse f lst)
(let loop ((result '())
(rest lst))
(if (null? rest)
(reverse result)
(loop (cons (f (car rest)) (cdr rest))))))
Alternatively, if your list-building is amenable to a "right-fold" recursive approach, that is also idiomatic:
(define (map-using-recursion f lst)
(let recur ((rest lst))
(if (null? rest)
'()
(cons (f (car rest)) (recur (cdr rest))))))
The above code snippets are just for illustrating the solution approach to take in the general case; for things that are directly implementable using fold, like map, using fold is more idiomatic:
(define (map-using-cons-and-reverse f lst)
(reverse (foldl (lambda (item result)
(cons (f item) result))
'() lst)))
(define (map-using-recursion f lst)
(foldr (lambda (item result)
(cons (f item) result))
'() lst))
How frequent do you have to append to the end?
If you want to do it a lot (more than cons'ing to the front), then you are doing it wrong. The right way is to flip things around: think that cons put things to the back, first retrieves the last element, rest retrieves everything but last, etc. Then, you can use list normally.
However, if you want to put things to the end of the list as frequent as to cons things to the front, then this is the best that you can do with one list. You could write a function to wrap what you consider "inelegant". Traditionally it's called snoc (backward cons)
(define (snoc lst e) (append lst (list e)))
Or if you prefer to implement the whole thing by yourself:
(define (snoc lst e)
(cond
[(empty? lst) (list e)]
[(cons? lst) (cons (first lst) (snoc (rest lst) e))]))
Note that both approaches have the same time complexity: O(n) where n is length of the list.
But if you want it to be efficient, you can use a data structure called double-ended queue, which is very efficient (constant time per operation). See http://www.westpoint.edu/eecs/SiteAssets/SitePages/Faculty%20Publication%20Documents/Okasaki/jfp95queue.pdf for more details.

How to convert the explicit recursive functions into Higher-Order/Abstract Functions in Scheme

I am wondering how to convert the explicit recursive functions below into a higher-ordered/abstract functions using foldr, map, filter, etc in Scheme/Racket.
(define (insertNoDups f element lst)
(cond[(empty? lst) (cons element lst)]
[(f element (first lst)) lst]
[else (cons (first lst)
(insertNoDups f element (rest lst)))]))
(define (remove-dups f lst)
(cond[(empty? lst) empty]
[else (insertNoDups f
(first lst)
(remove-dups f (rest lst)))]))
insertNoDups (rename it to insert-no-dups) : use member-procedure predicate (more info -> http://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Searching-Lists.html) and cons element to the front if not found.
remove-dups: look at Óscar López's answer here -> How to remove all the duplicates in a list using scheme (only abstract list functions allowed) and use member-procedure predicate instead of member?

What is "named let" and how do I use it to implement a map function?

I'm totally new to Scheme and I am trying to implement my own map function. I've tried to find it online, however all the questions I encountered were about some complex versions of map function (such as mapping functions that take two lists as an input).
The best answer I've managed to find is here: (For-each and map in Scheme). Here is the code from this question:
(define (map func lst)
(let recur ((rest lst))
(if (null? rest)
'()
(cons (func (car rest)) (recur (cdr rest))))))
It doesn't solve my problem though because of the usage of an obscure function recur. It doesn't make sense to me.
My code looks like this:
(define (mymap f L)
(cond ((null? L) '())
(f (car L))
(else (mymap (f (cdr L))))))
I do understand the logic behind the functional approach when programming in this language, however I've been having great difficulties with coding it.
The first code snippet you posted is indeed one way to implement the map function. It uses a named let. See my comment on an URL on how it works. It basically is an abstraction over a recursive function. If you were to write a function that prints all numbers from 10 to 0 you could write it liks this
(define (printer x)
(display x)
(if (> x 0)
(printer (- x 1))))
and then call it:
(printer 10)
But, since its just a loop you could write it using a named let:
(let loop ((x 10))
(display x)
(if (> x 0)
(loop (- x 1))))
This named let is, as Alexis King pointed out, syntactic sugar for a lambda that is immediately called. The above construct is equivalent to the snippet shown below.
(letrec ((loop (lambda (x)
(display x)
(if (> x 0)
(loop (- x 1))))))
(loop 10))
In spite of being a letrec it's not really special. It allows for the expression (the lambda, in this case) to call itself. This way you can do recursion. More on letrec and let here.
Now for the map function you wrote, you are almost there. There is an issue with your two last cases. If the list is not empty you want to take the first element, apply your function to it and then apply the function to the rest of the list. I think you misunderstand what you actually have written down. Ill elaborate.
Recall that a conditional clause is formed like this:
(cond (test1? consequence)
(test2? consequence2)
(else elsebody))
You have any number of tests with an obligatory consequence. Your evaluator will execute test1? and if that evaluated to #t it will execute the consequence as the result of the entire conditional. If test1? and test2? fail it will execute elsebody.
Sidenote
Everything in Scheme is truthy except for #f (false). For example:
(if (lambda (x) x)
1
2)
This if test will evaluate to 1 because the if test will check if (lambda (x) x) is truthy, which it is. It is a lambda. Truthy values are values that will evaluate to true in an expression where truth values are expected (e.g., if and cond).
Now for your cond. The first case of your cond will test if L is null. If that is evaluated to #t, you return the empty list. That is indeed correct. Mapping something over the empty list is just the empty list.
The second case ((f (car L))) literally states "if f is true, then return the car of L".
The else case states "otherwise, return the result mymap on the rest of my list L".
What I think you really want to do is use an if test. If the list is empty, return the empty list. If it is not empty, apply the function to the first element of the list. Map the function over the rest of the list, and then add the result of applying the function the first element of the list to that result.
(define (mymap f L)
(cond ((null? L) '())
(f (car L))
(else (mymap (f (cdr L))))))
So what you want might look look this:
(define (mymap f L)
(cond ((null? L) '())
(else
(cons (f (car L))
(mymap f (cdr L))))))
Using an if:
(define (mymap f L)
(if (null? L) '()
(cons (f (car L))
(mymap f (cdr L)))))
Since you are new to Scheme this function will do just fine. Try and understand it. However, there are better and faster ways to implement this kind of functions. Read this page to understand things like accumulator functions and tail recursion. I will not go in to detail about everything here since its 1) not the question and 2) might be information overload.
If you're taking on implementing your own list procedures, you should probably make sure they're using a proper tail call, when possible
(define (map f xs)
(define (loop xs ys)
(if (empty? xs)
ys
(loop (cdr xs) (cons (f (car xs)) ys))))
(loop (reverse xs) empty))
(map (λ (x) (* x 10)) '(1 2 3 4 5))
; => '(10 20 30 40 50)
Or you can make this a little sweeter with the named let expression, as seen in your original code. This one, however, uses a proper tail call
(define (map f xs)
(let loop ([xs (reverse xs)] [ys empty])
(if (empty? xs)
ys
(loop (cdr xs) (cons (f (car xs)) ys)))))
(map (λ (x) (* x 10)) '(1 2 3 4 5))
; => '(10 20 30 40 50)

Scheme: high order procedure and recursion

I'm using scheme as part of a course I'm taking. I've been told to use high order functions in my homework. However this instruction seems somewhat unclear.
I don't fully understand the idea of a high order procedure. I'm able to do all the questions using recursion but that it's the same thing. Can anyone explain it with an example of a recursive function vs one written with a high order procedure.
As a second question:
Example: try to grab all the odd numbers
I could use (flatten (map odd ((1 4 5) (4 5 1 4 9)))), but what if there were nested lists, can I use map on a nested lists like:
(flatten (map odd ((1 3 (9 5 7)))) ; is there a function for this or a clean way to do it?
The point of a higher-order function is to reduce the boilerplate in your code, and to decrease coupling between the looping (technically it's a recursion, but its purpose is looping, so I will refer to it as such) and the actual logic. Here's an example (re grabbing all the odd numbers): a manual loop would look like this:
(define (filter-odd lst)
(cond ((null? lst) '())
((odd? (car lst)) (cons (car lst) (filter-odd (cdr lst))))
(else (filter-odd (cdr lst)))))
But notice that you've got the looping and the filtering in one function. This makes it harder to figure out what the function is doing, since these two unrelated operations are coupled together. With higher-level functions, you can do differently:
(define (filter pred lst)
(cond ((null? lst) '())
((pred (car lst)) (cons (car lst) (filter pred (cdr lst))))
(else (filter pred (cdr lst)))))
(define (filter-odd lst)
(filter odd? lst))
Notice now, how odd? is separated from the looping logic, which has now been separated into filter? filter now takes a function object which decides whether the item is to be kept or not, and callers of filter can slot in any function of their choice.
That is what is meant by a higher-order function: it's a function that takes a function object as a parameter, to customise its operation.
As mentioned in the original edit of your question, map is another higher-order function, but instead of filtering items from a list, it returns a transformation of every item in the original list, where the specific transformation is given by map's caller via a parameter.
To answer your actual question about flattening, etc., (map filter-odd '((1 3 (9 5 7)))) will return a list with a single item, the result of calling (filter-odd '(1 3 (9 5 7))). So no, map will not recurse into sublists for you (and neither will filter).
But you can flatten the input first (since you're flattening the output anyway), then call filter-odd on that directly. I hope that will give you the result you expect.
(I renamed your odd to filter-odd, since that is less likely to be confused with odd? (the predicate).)
Bonus material
By the way, both filter and map are specialisations of a much more general higher-order function, called a fold (or more specifically, a right-fold). Folds can express things that cannot be accommodated by either filter or map, but that somehow involve traversing all the items in a list. Here's an example of a length function, expressed as a fold:
(define (foldl func init lst)
(if (null? lst) init
(foldl func (func (car lst) init) (cdr lst))))
(define (length lst)
(foldl (lambda (elem count)
(+ count 1))
0 lst))
The benefit here is that the length function does not have to worry about traversing the list: that is handled by the fold. It only needs to worry about what to do at each iteration (which, here, is simply adding 1 to count, which starts out as 0).
In this case, the length is the same whether we traverse from the left or the right, and in Scheme, traversing from the left is more space-efficient, so we prefer that. But for implementing map and filter, a right-fold is necessary (otherwise the elements come out reversed---try substituting the foldr with foldl in the below functions and you'll see):
(define (foldr func init lst)
(if (null? lst) init
(func (car lst) (foldr func init (cdr lst)))))
(define (map func lst)
(foldr (lambda (elem result)
(cons (func elem) result))
'() lst))
(define (filter pred lst)
(foldr (lambda (elem result)
(if (pred elem)
(cons elem result)
result))
'() lst))

Resources