semantic list in scheme - scheme

I am currently working on a implementing a standard semantic network and am beyond lost.
I have a global assc list:
(define *database* '())
and am trying to populate the list with the standard form as
((hellipcopter (isa (air-vehicle))
(has-part (propeller door)))
.
.
.
From The statements
(has-part helicopter propeller)
(has-part helicopter door)
(isa helicopter air-vehicle)
Here is my attempt
(define (process-relation rel)
(set! *database* (cons (cons (cons (cadr rel) (car rel)) (caddr rel))*database*)))
which prints out in this terrible fashion
((helicopter . has-part) . propeller)
((propeller . has-part) . blade)
I am new to scheme as you can tell, so i have some questions.
Why does cons form the statement like it does? (x . y)
How would you add a multiple parts, for instance, to the same object?
What would be the steps to fix this?

A list is a chain of cons. eg. if you evaluate '(1 . (2 . (3 . ()))) you get (1 2 3) since while the reader reads both dotted form and list form, the printer prints list form where it can. eg. if the cdr is a pair or () it omits the . and one pair of parentheses. If the last element in the chain is not () it is not a proper list and would require the dot form even for print. eg. '(1 . (2 . 3)) is (1 2 . 3).
(list 1 2 3) is the same as (cons 1 (cons 2 (cons 3 '())))
To fix you code some places you use cons you shoud use list or add more cons so that the values are only in the car position.

Related

in scheme what is the meaning of dot not on cons? why sometimes it is valid and sometime not

what is the meaning of dot, other than just cons notation?
dot as I know is just cons notation. so I don't understand the meaning here:
why:
> (equal? . 8)
Exception: invalid syntax (equal? . 8)
Type (debug) to enter the debugger.
but:
> (equal? . ((quote . ((a . (b . (c . ()))))) . ('(a b c))))
#t
what is the meaning of the dot here?
The syntax gets parsed and for a Scheme reader '(1 . (2 . ())) gets parsed and creates the same structure as '(1 2). Basically proper lists are singly linked lists where the last cdr points to the empty list.
(somefun . (5)) is the same as (somefun 5) for the reader. When the source code is turned in to a data structure, the interpreter won't know if you wrote the one or the other. Hovever (somefun . 5) doesn't get parsed to a function with one argument since the argument list itself is a number. the parser parsed it into a data structure, but your scheme implementation responsible to compile it or interpret it failed. You may use dotted list in data and some syntax like lambda for rest arguments, but it is very limited. Most of the time using dotted pairs in code fails.
A Scheme system will display structure only one way. eg. if you put in '(1 . (2 . ())) you will se (1 2) back since a dot with a list or empty list cdr gets special list visualization. If you do '(1 . (2 . 3)) it can start using the special rule since the cdr is a pair, but the next won't fly ending it up as (1 2 . 3). If you evaluate '(equal? . ((quote . ((a . (b . (c . ()))))) . ('(a b c)))) you get (equal? '(a b c) '(a b c)) back and that is because it is the simplest visualization of that structure. As code they read to the same structure and evaluate the same.
The most common problem when learning Scheme is to understand the list structure. Eg. how to create ((1 2) (3 4)) using cons and how to access the 4. If you knew it is really ((1 . (2 . ()) . ((3 . (4 . ())))) you see the 4 is after fllowing the cdr, car, cdr, then car or the simplified (cadadr '((1 2) (3 4))). The visualizer will just omit the dot and the extra set of parentheses in the cdr if it has them. eg. '((a) . (b)) will become ((a) b)

Update list in racket without hash

I have the 2 lists, '(1 2 3 4), and '(add1 sub1 add1). They do not have same length. The first list is numbers, the second list is functions. I want to apply the functions to each of element in the number list.
'(1 2 3 4) (add1 sub1 add1) -> '(2 3 4 5) '(sub1 add1)
It look very simple, but I find I can not update the lists. Because in Scheme there is no way to update lists without hash. I can only create new lists. So every time I have to create a new list for each function in the second list. Can someone help me code this question?
Alternatively you could use map and compose in combination.
This is much easier to read and understand.
(map (compose add1 sub1 add1) '(1 2 3 4))
;; '(2 3 4 5)
(compose add1 sub1 add1) chains the functions one after another
and map applies this chained/composed function on each element of the input list '(1 2 3 4).
Generalize to a function:
(define (map-functions funcs . args)
(apply map (apply compose funcs) args))
(map-functions (list add1 sub1 add1) '(1 2 3 4)) ;; '(2 3 4 5)
compose is inbuilt but one can define it like this (% in names to not to overwrite the existing compose.
;; first a compose to compose to functions
(define (%%compose f1 f2)
(lambda args
(f1 (apply f2 args))))
;; then, generalize it for as many functions as one wants (as a variadic function) using `foldl`
(define (%compose . funcs)
(foldl %%compose (car funcs) (cdr funcs)))
You're looking for a left fold. It looks like Racket calls it foldl, which will do the job, combined with map. Something like (Untested, because I don't have Racket installed):
(define functions (list add1 sub1 add1)) ; So you have functions instead of symbols like you get when using quote
(define numbers '(1 2 3 4))
(foldl (lambda (f lst) (map f lst)) numbers functions)
Basically, for each function in that list, it maps the function against the list returned by mapping the previous function (Starting with the initial list of numbers when there is no previous).
If you're stuck with a list of symbols and can't use the (list add1 ... trick to get references to the actual functions, one approach (And I hope there are better ones) is to use eval and some quasiquoting:
(foldl (lambda (f lst) (eval `(map ,f (quote ,lst)))) '(1 2 3 4) '(add1 sub1 add1))

How to use format's iteration ability on a list of conses

I know that I can use format's ~:{ ~} operator to process a list of lists directly, e.g.
CL-USER> (format t "~:{<~A,~A> ~}~%" '((1 2) (3 4)))
<1,2> <3,4>
But now I have a list of conses, e.g. ((1 . 2) (3 . 4)) and the expression
(format t "~:{<~A,~A> ~}~%" '((1 . 2) (3 . 4)))
leads to SBCL complaining
The value
2
is not of type
LIST
Is there any format magic doing the trick without having to use an extra iteration with do or loop?
I see basically 4 options
Do not use format for the whole list
The straightforward solution is avoid the problem:
(loop
for (k . v) in '((1 . 2) (3 . 4))
do (format t "<~a,~a> " k v))
Custom format function
Alternatively, use Tilde Slash to call a function that prints cons-cells:
(defun cl-user::pp-cons (stream cons colonp atsignp)
(declare (ignore colonp atsignp))
(format stream "~a, ~a" (car cons) (cdr cons)))
(format nil "~/pp-cons/" (cons 1 2))
=> "1, 2"
Note that the function must be in the CL-USER package if you don't specify the package. If you want to customize how cells are printed, you need to pass the format through a special variable:
(defvar *fmt* "(~s . ~s)")
(defun cl-user::pp-cons (stream cons colonp atsignp)
(declare (ignore colonp atsignp))
(format stream *fmt* (car cons) (cdr cons)))
And then:
(let ((*fmt* "< ~a | ~a >"))
(format t "~/pp-cons/" (cons 1 2)))
=> < 1 | 2 >
Convert on printing
Build a fresh list, where improper lists are replaced by proper lists:
(format t
"~:{<~a,~a> ~}~%"
(series:collect 'list
(series:mapping (((k v) (series:scan-alist '((1 . 2) (3 . 4)))))
(list k v))))
The drawback is that the conversion needs to allocate memory, just for printing.
Change your data format
If proper lists are good for printing, maybe they are good for other operations too. A lot of standard functions expect proper lists. Note that the list ((1 2) (3 4)) is still an alist, the value is just wrapped in a cons-cell. If you decide to use this format from the start, you won't have to convert your lists.

Scheme create list of pairs using foldr without explicit recursion

I am learning a course of Scheme and have to do the following task. I have to write a function that gets two lists A and B in the same length and returns one list that every item inside is a list of two items - one from A and second from B.
For example the function gets '( 1 2 3) and '(4 5 6) and returns '((1 4)(2 5)(3 6)).
I can do that using map like this:
(define (func lst1 lst2) (map (lambda(x y) (list x y)) lst1 lst2))
But the the question is to do that by foldr and without explicit recursion.
Can anyone please help me? I have no idea how to do that....
Thanks!
The trick is knowing what to pass as a function parameter, here's how:
(define (func l1 l2)
(foldr (lambda (e1 e2 acc)
(cons (list e1 e2) acc))
'()
l1 l2))
Notice that we're passing two lists at the end of foldr, so the lambda expects three parameters: the current element from the first list (e1), the current element from the second list (e2) and the accumulated output (acc), which starts with value '(). The rest is easy, just build the output along using cons and list. It works as expected:
(func '(1 2 3) '(4 5 6))
=> '((1 4) (2 5) (3 6))

On Scheme cons and dots notation

Given
#;> (cons (cons 1 2) 3)
((1 . 2) . 3)
When we try
#;> (cons 3 (cons 1 2))
(3 1 . 2)
What governs where the . is used? What would the memory representation of these constructs be?
Scheme implementations usually print things that look like lists in list form:
-> (cons 1 (cons 2 '()))
'(1 2)
In your example, (cons 3 (cons 1 2)) would be a list if it weren't for the last 2. So your implementation makes a best effort to print it as a list until the 2. The other example does not contain any part that looks like a list, so it just prints as nested pairs.

Resources