How would I return a list that takes two lists and associates them with the contents in that list together in plait language for Racket? - racket

I'm working on a problem that has me using Racket with plait language and I'm trying to get a program that takes two lists and associate them together like this. I am relatively new to Racket and the plait language.
'(a b c d) and '(1 2 3 4)
Together they should output:
'((make-assoc 'a 1) (make-assoc 'b 2) (make-assoc 'c 3) (make-assoc 'd 4)))
This is what I have defined so far:
#lang plait
(define-type Associate
(assoc [name : Symbol]
[values : Number]))
(define (make-assoc [names : (Listof Symbol)] [values : (Listof Number)]): (Listof assoc)
(map (lambda (name value) (assoc name value)) names values))
(test (make-assoc '(a b c d) '(1 2 3 4))
'((make-assoc 'a 1) (make-assoc 'b 2) (make-assoc 'c 3) (make-assoc 'd 4)))
(test (make-assoc '(t a c o tuesday) '(0 1 34 1729 42))
'((make-assoc 't 0) (make-assoc 'a 1) (make-assoc 'c 34) (make-assoc 'o 1729) (make-assoc 'tuesday 42)))
I tried to get somewhere coming up stuff for make-assoc but I am having trouble with syntax and I guess I can't use map or lambda because make-assoc is already the identifier. So maybe I could use append in some way?

First of all, the type is Associate, not assoc.
assoc is the name of its only variant, and is used to construct values of the Associate type.
> assoc
- (Symbol Number -> Associate)
#<procedure:assoc>
> (assoc 'hello 1234)
- Associate
(assoc 'hello 1234)
So you should have
(define (make-associate [names : (Listof Symbol)] [values : (Listof Number)]): (Listof Associate)
...
(You also need to rename it, as make-assoc is already taken by the "machinery".)
Second, the type of map is
(('a -> 'b) (Listof 'a) -> (Listof 'b))
so it takes a one-argument function and one list and produces a list.
You want map2, which has the type
(('a 'b -> 'c) (Listof 'a) (Listof 'b) -> (Listof 'c))
So,
(define (make-associate [names : (Listof Symbol)] [values : (Listof Number)]): (Listof Associate)
(map2 (lambda (name value) (assoc name value)) names values))
Third, quoting "suspends" evaluation; '(a b) is not the same as (list a b) – the former is a list of the symbols a and b while the latter is a list of the values those symbols are bound to.
> (define a 1)
> a
- Number
1
> 'a
- Symbol
'a
> (list a)
- (Listof Number)
'(1)
> '(a)
- (Listof Symbol)
'(a)
So you want to use list rather than ' in your test cases.
You also use assoc, not make-assoc, to create values of the Associate type.
In summary:
(test (make-associate '(a b c d) '(1 2 3 4))
(list (assoc 'a 1)
(assoc 'b 2)
(assoc 'c 3)
(assoc 'd 4)))
(test (make-associate '(t a c o tuesday) '(0 1 34 1729 42))
(list (assoc 't 0)
(assoc 'a 1)
(assoc 'c 34)
(assoc 'o 1729)
(assoc 'tuesday 42)))
And now,
good (make-associate '(a b c d) '(1 2 3 4)) at line 10
expected: (list (assoc 'a 1) (assoc 'b 2) (assoc 'c 3) (assoc 'd 4))
given: (list (assoc 'a 1) (assoc 'b 2) (assoc 'c 3) (assoc 'd 4))
good (make-associate '(t a c o tuesday) '(0 1 34 1729 42)) at line 14
expected: (list (assoc 't 0) (assoc 'a 1) (assoc 'c 34) (assoc 'o 1729) (assoc 'tuesday 42))
given: (list (assoc 't 0) (assoc 'a 1) (assoc 'c 34) (assoc 'o 1729) (assoc 'tuesday 42))

Related

typed/racket + racket interoperability

How can I use typed Racket for some functions in my codebase, but use (untyped) Racket for others? When I define a function in Racket but import it into a typed Racket context, it seems to be changing the behavior of the function (functions described below).
As it is now, the files do typecheck, but don't pass my tests in p11typedtest.rkt -- however, my files do successfully pass my tests if I either (A) switch p11typed.rkt to regular Racket or (B) copy the pack function into p11typed.rkt and provide its type annotation.
;; p09.rkt
#lang racket
(provide pack)
;; packs consecutive duplicates within a list into sublists
(define (pack lst)
(for/foldr ([acc '()]) ([x lst])
(match acc
[(cons (cons y ys) zs) #:when (equal? x y)
(list* (list* x y ys) zs)]
[_ (list* (list x) acc)]
)))
;; p11typed.rkt
#lang typed/racket
(provide encode-runlen-mod)
;; (require (only-in (file "p09.rkt") pack))
(require/typed (only-in (file "p09.rkt") pack)
[pack (All (A) (-> (Listof A) (Listof (Listof A))))]
)
(define-type (Runof a) (List Index a))
(define-type (RunListof a) (Listof (U a (Runof a))))
;; encodes a list as a list of runs
(: encode-runlen-mod (All (A) (-> (Listof A) (RunListof A))))
(define (encode-runlen-mod lst)
;; uncomment to print the result of pack
;; (displayln (pack lst))
(for/list ([dups (pack lst)])
(match (length dups)
[1 (car dups)]
[n (list n (car dups))]
)))
; (: pack (All (A) (-> (Listof A) (Listof (Listof A)))))
; (define (pack lst)
; (for/foldr ([acc '()]) ([x lst])
; (match acc
; [(cons (cons y ys) zs) #:when (equal? x y)
; (list* (list* x y ys) zs)]
; [_ (list* (list x) acc)]
; )))
;; p11typedtest.rkt
#lang racket
(require (only-in (file "p11typed.rkt") encode-runlen-mod))
(define (test-output namespace expr v)
(let* ([val (eval expr namespace)]
[fail (not (equal? val v))])
(begin
(display (if fail "FAIL" "ok "))
(display " '(=? ")
(print expr)
(display " ")
(print v)
(display ")'")
(if fail
(begin
(display ", got ")
(print val)
(displayln " instead")
)
(displayln "")
)
(void))
))
(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))
(test-output ns '(encode-runlen-mod '(1 2 3 4)) '(1 2 3 4))
(test-output ns '(encode-runlen-mod '(1 1 1)) '((3 1)))
(test-output ns '(encode-runlen-mod '(1 2 2 3 4)) '(1 (2 2) 3 4))
(test-output ns '(encode-runlen-mod '(1 2 3 4 4 4)) '(1 2 3 (3 4)))
(test-output ns '(encode-runlen-mod '(1 2 3 (3 4))) '(1 2 3 (3 4)))
(test-output ns '(encode-runlen-mod '(A A A A B C C A A D E E))
'((4 A) B (2 C) (2 A) D (2 E)))
)

Can you get dot representation using 'list' command in LISP?

I understand that by using cons we could have something like :
> (cons 'b 'c)
(B . C)
And that happens because the cell is split into two and the values are B and C.
My question is, can you get the same result using list?
You can't get list to return a dotted list, because "the last argument to list becomes the car of the last cons constructed" in the returned list.
But, you can get list* to return a dotted list. With the list* function, the final argument becomes the cdr of the last cons, so:
CL-USER> (list* 'a '(b))
(A B)
CL-USER> (list* 'a 'b '())
(A B)
CL-USER> (list* 'a 'b)
(A . B)
CL-USER> (list* 'a '(b c))
(A B C)
CL-USER> (list* 'a 'b '(c))
(A B C)
CL-USER> (list* 'a 'b 'c '())
(A B C)
CL-USER> (list* 'a 'b 'c)
(A B . C)
For example, (list* 'a 'b 'c '()) and (list 'a 'b 'c) are both equivalent to:
CL-USER> (cons 'a (cons 'b (cons 'c '())))
(A B C)
But (list* 'a 'b 'c) is equivalent to:
CL-USER> (cons 'a (cons 'b 'c))
(A B . C)
And, (list* 'a 'b) is equivalent to:
CL-USER> (cons 'a 'b)
(A . B)
No you can't, because a list is a list of cons cells whose last cdr is nil. The Lisp printer knows the convention and doesn't print a dot in that case.
;; a cons cell
CL-USER> (cons 'b 'c)
(B . C)
[o|o]--- c
|
b
;; two cons cells, ending with a symbol: a dot.
CL-USER> (cons 'b (cons 'c 'd))
(B C . D)
;; several cons cells, ending with a symbol: still a dot (at the last cons cell):
CL-USER> (cons 'b (cons 'c (cons 'd (cons 'e 'f))))
(B C D E . F)
;; two cons cells, ending with nil: no dot.
CL-USER> (cons 'b (cons 'c nil))
(B C) ;; and not (B C . NIL)
[o|o]---[o|/]
| |
b c
;; with the list constructor:
CL-USER> (list 'b 'c)
(B C)
https://lispcookbook.github.io/cl-cookbook/data-structures.html#building-lists-cons-cells-lists

Racket List Questio

Does anyone know how to return a number of specific elements in a list?
Example: given
(list 'a 'a 'a 'a 'a 'b 'b 'b)
Returns the numbers of 'a: 5
numbers of 'b: 3
You count them. You make a procedure that takes a list and what you want to search for and you iterate that list while keeping a count and when you reach the end you return that value.
A skeleton for a simple recursive solution:
(define (count-element element lst)
(define (helper lst count)
(cond ((empty? lst) count)
((equal? element <first element>) <recurse whith cdr and increasing count>)
(else <recurse with cdr>)))
(helper lst 0))
Or you can use foldl
(define (count-element element lst)
(foldl (lambda (e count)
(if <e is the same as element>
<return 1 more than count>
<return count>))
0
lst))
There are probably 10 more ways I could do it, but the first is the most educational and the second the most common way I would do it.
Some tests:
(define test '(a a a a a b b b))
(count-element 'b '()) ; ==> 0
(count-element 'e test) ; ==> 0
(count-element 'a test) ; ==> 5
(count-element 'b test) ; ==> 3
I somewhat managed to find the answer, so here's the function definition:
(define (number-of s L)
(cond
[(empty? L) 0]
[else (cond [(eq? s (first L)) (+ 1 (number-of s (rest L)))]
[else (number-of s (rest L))])]))

LISP List Not Appending And Printing Twice

I'm quite new to LISP and I am trying to work on the cond statement for class. Currently, I am attempting to check if the value passed is a list and if so, append the letter d onto the list.
Here is my code:
(defun test(L)
(listp L)
(cond ((listp L) (append L (list 'd)))
)
(write L)
)
(test (list 'a 'b 'c))
The output I get is:
(A B C)
(A B C)
If I change the test to: (test (car(list 'a 'b 'c)))
The new output I get is:
A
A
Two things I am wondering is
1.) Why isn't D appended onto the list if the first test passes a list?
2.) Why are they being printed twice? I'm using LISP Works so I figure it's actually something with how it always outputs the final value or something.
1.) The same reason str + "d" doesn't mutate str in Java or Python. It creates a new list that you do not use!
>>> str + "d"
'abcd'
>>> str
'abc'
Crazy similar isn't it?
2.) In CL the return is the last evaluated expression. The REPL prints every top level expression result to the terminal. Python does this too:
>>> def test():
... x = 2 + 3
... print x
... return x
...
>>> test()
5
5
Update
How to mutate the argument list. The simple answer is that you need to mutate the last pair of the argument instead:
(defun test (l)
(assert (consp 1) (l) "l needs to be a non nil list. Got: ~a" l)
(nconc l (list 'd)
(write l)))
(defparameter *test1* (list 1 2 3))
(defparameter *test1-copy* *test1*)
(test *test1*) ; ==> (1 2 3 d) (and prints (1 2 3 d))
*test1* ; ==> (1 2 3 d)
*test1-copy* ; ==> (1 2 3 d)
(eq *test1* *test1-copy*) ; ==> t
(test '())
** error l needs to be a non nil list. Got: NIL
(nconc l x) does (setf (cdr (last l)) x)
If you need to alter the binding, then you need to make a macro:
(defmacro testm (var)
(assert (symbolp var) (var) "List needs to be a variable binding. Got: ~a" var)
`(progn
(when (listp ,var)
(setf ,var (append ,var (list 'd)))
(write ,var))))
(macroexpand '(testm *test2*))
; ==> (progn
; (when (consp *test2*)
; (setf *test2* (append *test2* (list 'd))))
; (write *test2*))
(defparameter *test2* (list 1 2 3))
(defparameter *test2-copy* *test2*)
(testm *test2*) ; ==> (1 2 3 d) (and prints (1 2 3 d))
*test2* ; ==> (1 2 3 d)
*test2-copy* ; ==> (1 2 3)
(eq *test2* *test2-copy*) ; ==> nil
(defparameter *x* nil)
(testm *x*) ; ==> (d) (and prints (d))
*x* ; ==> (d)
(testm '(1))
** error List needs to be a variable binding. Got: '(1)
Idiomatic way to do it
(defun test (list)
(if (consp list)
(append list '(d))
list))
(write (test '(1 2 3)))
; ==> (1 2 3 d) (and prints (1 2 3 d))
(defparameter *test3* '(1 2 3))
(setf *test3* (test *test3*))
*test3* ; ==> (1 2 3 d)

Racket duplicator function

I'm writing a duplicator function using racket. The duplicator function takes a nested list of symbols and numbers L, and produces a nested list of symbols and numbers by "immediately duplicating" each atom (symbol or number) at all levels.
For example:
(duplicator '(a 1 b 2 c 3)) produces (a a 1 1 b b 2 2 c c 3 3),
(duplicator '( (a 1) b ((c)) 2) produces ( (a a 1 1) b b ((c c)) 2 2).
Here is my function:
(define (duplicator ls)
(if (null? ls)
'()
(cons (car ls)
(cons (car ls)
(duplicator (cdr ls))))))
The problem I have is the output for (duplicator '( (a 1) b ((c)) 2)) is '((a 1) (a 1) b b ((c)) ((c)) 2 2), which is not what I want.
Can anyone tell me how to get it right, please?
Here is a solution:
(define (duplicator ls)
(cond ((null? ls) '())
((list? (car ls)) (cons (duplicator (car ls)) (duplicator (cdr ls))))
(else (cons (car ls) (cons (car ls) (duplicator (cdr ls)))))))
(duplicator '((a 1) b ((c)) 2)) ; produces ((a a 1 1) b b ((c c)) 2 2)