How to create a dictionary mapping on custom dictionary in Racket? - list

I have defined dictionary as this judgment in BNF grammar:
d ::= () (any boolean) (list cons d d)
Meaning, dictionaries are empty, or (any boolean) or a list of such pairs.
If I want to create a mapping, say "a true", how do I do it?
If I do
(define-values (d) (values '(a true)))
it just creates a new d, doesn't map to previous judgment d defined.

IIUC you want your dictionary to be just an association list:
(define d (list (cons 'x #t) (cons 'y #f)))
Depending on how are you going to implement the add operation you could either set! a new mapping:
(set! d (cons (cons 'z #t) d))
Or just create a new list (preferred):
(define d (list (cons 'z #t) (cons 'x #t) (cons 'y #f)))
Either way, the dictionary d will have the new mapping in the expected format:
'((z . #t) (x . #t) (y . #f))

Related

Lisp - Get rid of dotted list

I am building a function is Lisp ta reverses the first and last element of a list. I get that a list has a car and a cdr hence why there is a dot in my output. Is there a way to remove the dot?
(defun my-butlast (list)
(loop for l on list
while (cdr l)
collect (car l)))
(defun f-l-swap(list)
(append (last list)(cdr (my-butlast list))(car list))
)
(write(f-l-swap '(A B C D E)))
OUTPUT:
(E B C D . A)
append expects arguments to be lists. In your case (car list) is an atom. You have to change it to list if you want to stick with append. Ie:
(defun f-l-swap (list)
(append (last list)
(cdr (my-butlast list))
(list (car list))))
A list is a chain of cons pairs. eg. (1 2 3) is the visualization of (1 . (2 . (3 . ()))). In the event the last cdr is not () you have what we call a dotted list since then there is no simplified visualization of the last part. It has to be printed with a dot.
You have (E . (B . (C . (D . A)))) and want to have (E . (B . (C . (D . (A . ()))))). Do you see the difference? (car list) is not a list but one elment and that is why you get a dotted list.
Here are more sensible implementations of append and butlast:
(defun my-append (a b)
(if (null a)
b
(cons (car a) (my-append (cdr a) b))))
That only supports 2 arguments, but the idea for more is that it continues until you have consed all the previous lists and only have one left, which verbatim becomes the tail. Here is how that might look:
(defun my-append2 (x &rest xs)
(labels ((helper (x xs)
(cond ((null xs) x)
((null x) (helper (car xs) (cdr xs)))
(t (cons (car x) (helper (cdr x) xs))))))
(helper x xs)))
Here is butlast
(defun my-butlast (xs)
(if (null (cdr xs))
'()
(cons (car xs) (my-butlast (cdr xs)))))
Now, one should really do it with higher order functions or loop, but then you get the facts hidden how lists work. The code above shows you have they work.

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)))

Every other letter in a list? LISP

I am relatively new to LISP and am trying some new things for a Lisp program I am trying to create for a presentation.
I need to be able to print every other character in a list, for example, (A B C D E F) would return (A C E) .. but I am getting easily confused...
I am normally program Java, so this comes kind of different to me.
I am trying to program this using purely recursion.. So something along the lines of....
(defun every-other (lst)
(cond ((null lst) 0)
(( **** now this is where I get confused as to what I should do..
I've tried adding a counter to only remove even numbered elements, but I think I implemented the counter wrong, I also tried remove(cadr lst) lst, but that would only return zeros...
any help would be greatly appreciated..
Thanks!
Since you say you want it to be done recursively, just think it through case by case.
The list is null -> return the empty list [the empty list is '()].
Otherwise the list is not null -> In this case you want to build a new list containing
the first element, skip the second element, then grab
every-other element of the remaining list.
Turning this case analysis into code looks something like this:
(defun every-other (lst)
(cond
;; If the list is null return the empty list.
((null lst) '())
;; If the list is not null, construct [cons] a new list with the first element of lst
;; and every-other element of the list after the first two elements [rest returns the
;; list without the first element, so we can just use it twice].
(t (cons (first lst) (every-other (rest (rest lst)))))))
Now going through the evaluation of this code should look something like this:
(every-other '(a b c d e f))
=> (cons 'a (every-other '(c d e f)))
=> (cons 'a (cons 'c (every-other '(e f))))
=> (cons 'a (cons 'c (cons 'e (every-other '())))
=> (cons 'a (cons 'c (cons 'e '())))
=> (cons 'a (cons 'c '(e)))
=> (cons 'a '(c e))
=> '(a c e)
For fun, a loop-based solution:
(defun every-other (lst)
(loop
for i in lst
for keep = t then (not keep)
if keep collect i))
Just use a loop.
(loop :for c :in '(a b c d e f) :by #'cddr
:collect c)
:By in a for-in clause sets the stepping function (default is #'cdr). In order to get every other element, step two steps each time. Cddr is a shortcut for applying cdr two times.
(defun aaa (x)
(aa (length x) x))
(defun aa (n x)
(cond ((null x) nil)
((evenp (- n (length x))) (cons (car x) (aa n (cdr x))))
(t (aa n (cdr x)))))
This is a stupid case lol~
shorter recursive solution:
(defun every-other (l)
(unless (null l)
(cons (first l) (every-other (cddr l)))))

A function which will determine that if a passed in list follows an A B pattern

(define fun4
(lambda ( ls)
(cond ((null? ls ) #f)
(cons (((eqv? 'a (car ls))) && ((eqv? 'b (cdr ls)))))
(else (pattern2 cdr ls)))))
In this it showing error - procedure application: expected procedure, given: #t (no arguments),
What is the erroe in my code. Is logic is fine ???
There are many, many errors in your solution. Let's see what's wrong in each of the conditions:
The base case of the recursion (empty list) is wrong: an empty list is the exit of the recursion, and it means that the list was traversed correctly and it follows the pattern
Another base case is missing: what if the list has a single element?
If the pattern doesn't hold, we must return #f immediately, and notice how we use cadr for accessing the second element, because && doesn't work in Scheme, you must use and for the logical and operation. Also you have unnecessary, erroneous parentheses surrounding each test (by the way: those were the ones causing the "expected procedure" error)
Only if none of the above conditions hold we advance the recursion, and we do so by moving two elements further down the list using cddr. Also you must call fun4 to advance the recursion, not pattern2
This is the correct way to solve the problem, notice how the above issues were addressed:
(define fun4
(lambda (ls)
(cond ((null? ls) #t) ; 1
((null? (cdr ls)) #f) ; 2
((not (and (eq? 'a (car ls)) (eq? 'b (cadr ls)))) #f) ; 3
(else (fun4 (cddr ls)))))) ; 4
Always test your procedures, the above will work correctly:
(fun4 '())
=> #t
(fun4 '(a))
=> #f
(fun4 '(a b))
=> #t
(fun4 '(a b a))
=> #f
(fun4 '(a b a b))
=> #t
As a final note, if the empty list is not supposed to follow the pattern, then check for it before calling fun4 and return #f if the initial input list is empty.
(define fun
(lambda (ls)
(cond ((null? ls) #t)
((and (eq? (car ls) 'a) ; the first item is a
(list? (cdr ls)) ; the rest of the list
(not (null? (cdr ls))) ; which is not null
(eq? (cadr ls) 'b) ; and it starts with b
(fun (cddr ls))) #t) ; and the rest of the expression is
(else #f)))) ; also in the A B format
Running:
> (fun '(a b a b))
#t
> (fun '(a b a))
#f
> (fun '(a b))
#t
> (fun '(a))
#f
> (fun '())
#t
>
So much wheel reinvention. Just use SRFI 1!
(require srfi/1)
(define (fun4 lst)
(every eq? lst (circular-list 'a 'b)))
(This operates under the assumption that (a b a) should be valid rather than invalid.)

Scheme: Return all elements of an expression that can be obtained using any combination of car and cdr

I'm trying to write a procedure in Scheme (R5RS) of my CS class that takes an expression (either a symbol or a list) as an argument and returns a list of (1) all the possible expression that can be formed by using car and cdr on the expression and (2) and an expression demonstrating how each of these components of the original expression were obtained. If a piece can be obtained in more than one way, it should be returned more than once.
Examples
(pieces '()) => ((() x))
(pieces 'apple) => ((apple x))
(pieces '(apple)) => (((apple) x) (apple (car x)) (() (cdr x)))
(pieces '(a (b c))) =>
(((a (b c)) x)
(a (car x))
(((b c)) (cdr x))
((b c) (car (cdr x)))
(b (car (car (cdr x))))
((c) (cdr (car (cdr x))))
(c (car (cdr (car (cdr x)))))
(() (cdr (cdr (car (cdr x)))))
(() (cdr (cdr x))))
Since we've just started with Scheme, we're limited to fairly basic syntax for this assignment. Here's what I have so far:
(define pieces
(lambda (exp)
(cond
((symbol? exp)
(list exp 'x))
((null? exp)
(list '() 'x))
((list? exp)
(let ((b (pieces (car exp))) (c (pieces (cdr exp))))
(list exp 'x b c))))))
(pieces '()) => (() x)
(pieces 'apple) => (apple x)
(pieces '(apple)) => ((apple) x (apple x) (() x))
(pieces '(a (b c))) => ((a (b c)) x (a x) (((b c)) x ((b c) x (b x) ((c) x (c x) (() x)))
(() x)))
The procedure returns all of the proper elements, but each recursion causes the components to be nested in an additional list. Is there any way to prevent that?
Also, I have no idea where to start for the second part of the problem (showing how each element was obtained from the original using car and cdr). I've tried a million different approaches, and none of them have even been close to working. If anyone has any hints or suggestions on how to implement that feature, I'd really appreciate it. Thanks a ton.
(pieces 'apple) => (apple x)
But it should be ((apple x)), right? You should get a list where the first and only element is the list (apple x).
The cond clauses that terminate recursion (exp is a symbol or null) return items that should go in the list, while the clause that recurs on car and cdr attempts to create a list of items. As pieces can return both items and lists of items it's kind of hard to make a list of items out of the values that are returned from it: when you do (list exp 'x b c) you don't know if b and c are items that should go into the list or lists of items.
If you make sure that pieces always returns a list of items (e.g. (list (list exp 'x))) it gets a lot easier. When you recur on car and cdr you want to do something like append the lists a and b and add the "current" ((list exp 'x)) item to that list (maybe with cons or something).
For the second part, pieces must know how it got to the current item. You can make pieces take a the "path" to the current item as a (maybe optional) parameter. If the path is a list, then when you call pieces on (car exp) you can add a car symbol to the path you're sending as argument, and for (cdr exp) you can add the symbol cdr. And then you use the path to create something nice to substitute for 'x in (list exp 'x).
I know it's not Scheme, but maybe looking at similar language would help. I did this more to practice myself, so take it with a drip of salt, yet it seems to be doing exactly what you're after:
(defun parse-list (whatever)
(labels ((pieces (expression &optional path)
(cond
((null expression)
`((,path . nil)))
((listp expression)
(append (list
`(,path . ,expression))
(pieces (car expression)
(cons 'car path))
(pieces (cdr expression)
(cons 'cdr path))))
(t `((,path . ,expression))))))
(dolist (output (pieces whatever))
(format t "path ~a => result ~a~&"
(car output) (cdr output)))))
(parse-list '(a (b c)))
Which then produces this output:
path NIL => result (A (B C))
path (CAR) => result A
path (CDR) => result ((B C))
path (CAR CDR) => result (B C)
path (CAR CAR CDR) => result B
path (CDR CAR CDR) => result (C)
path (CAR CDR CAR CDR) => result C
path (CDR CDR CAR CDR) => result NIL
path (CDR CDR) => result NIL
Sorry, I couldn't get SO's code formatting better than this :)