how to make HTML from a list in scheme, racket - recursion

This is a very long question ... I am new and joined, so please don't attack me. Apologies for my bad communications in English. I have some defintions:
An HTML(H) is one of
Str
Tag
A Tag is
(cons Sym (listof H))
I want to use mutual recursion,make the HTML into real HTML code. For example,
(list 'html (list 'head (list 'title "Hi")) (list 'body (list 'h1 "Welcome") "Text"))
Turns into:
"<html><head><title>Hi</title></head><body><h1>Welcome</h1>Text</body></html>"
This should work for any list or string. There are rules for turning it into HTML:
A string does not need to turn into HTML.
Each Tag (this is from the definitions) begin with <tag> and end with </tag>. So <html> and </html>.
If they enter a string, "Hello", then it does not convert anything. I wrote code here, but it does not work ...
(define (html->string html)
(cond [(string? html) html]
[else (append (list "<" (first html) ">") (change-tag (rest html)) (list "</" (first html) ">"))]))
(define (change-tag lst)
(cond [(empty? lst) empty]
[else (append (html->string (list (first lst)))
(html->string (list (rest lst))))]))
If I enter something like:
(list 'html (list 'head (list 'title "Hi")) (list 'body (list 'h1 "Welcome") "Text"))
Then it gives me:
(list "<" 'html ">" "<" (list 'head (list 'title "Hi")) ">" "</" (list 'head (list 'title "Hi")) ">" "<" (list (list 'body (list 'h1 "Welcome").....etc etc
It is a very long output and it does not work. How to be able to fix this?

You have the right idea, but still - there are three main issues with your proposed solution:
The output will be a string, not a list, so we must append strings in the recursive steps and return strings in the base cases.
Symbols must be explicitly converted to strings if we want to concatenate them with other strings.
And last but not least: you're missing a couple of base cases, and these are essential for writing a correct solution: what should happen if the given html is an empty list? What if the first element in a list is not a symbol, but another list?
This will work, take a careful look at the things that changed:
(define (html->string html)
(cond [(empty? html) ""]
[(string? html) html]
[(not (symbol? (first html)))
(html->string (first html))]
[else (string-append
"<" (symbol->string (first html)) ">"
(change-tag (rest html))
"</" (symbol->string (first html)) ">")]))
(define (change-tag lst)
(cond [(empty? lst) ""]
[else (string-append
(html->string (first lst))
(html->string (rest lst)))]))
It works as expected:
(define html
(list 'html
(list 'head
(list 'title "Hi"))
(list 'body
(list 'h1 "Welcome")
"Text")))
(html->string html)
=> "<html><head><title>Hi</title></head><body><h1>Welcome</h1>Text</body></html>"

Related

Scheme Lexical Parser

New to scheme and currently working on a lexical analyzer. Below is my code and I am getting the error
map: contract violation
expected: list?
given: #
argument position: 2nd
other arguments...:
#
#lang racket
(define tokens '((dog noun)
(cat noun)
(chases verb)
(the article)))
(define (getToken word)
(cadr (assq word tokens)))
(define ttw (lambda (l)
(map getToken l)))
(define (parse-sentence list)
(article list))
(define (article list)
(if (eq? (car list) 'article)
(begin
(display "Article: ")
(display (car list))
(noun (cdr list))
)
(begin
(display "Not an Article!!!")
(display (car list)))
))
(define (noun list)
(if (eq? (car list) 'noun)
(begin
(display "Noun:")
(display (car list))
(noun (cdr list))
)
"Not a noun!!!")
)
(begin
(display "Enter a Sentance in (): ")
(let ((input (read)))
(ttw (parse-sentence input))))
My input is (the dog chases the cat)
Running the program, I see that DrRacket colors this expression red:
(map getToken l)
which is part of the function
(define ttw (lambda (l)
(map getToken l)))
and since the error is
map: contract violation
expected: list?
given: #<void>
argument position: 2nd
other arguments...:
we now know that ttw is called with void as input and not a list as expected.
Where is ttw called? Clicking the "Check Syntax" icon (the check mark with the magnifying glass) and then hovering the mouse over ttw shows all uses.
The only use is in:
(ttw (parse-sentence input))
This means that parse-sentence returned void. Let's see the definition of parse-sentence:
(define (parse-sentence list)
(article list))
Okay, so the error must be in article:
(define (article list)
(if (eq? (car list) 'article)
(begin
(display "Article: ")
(display (car list))
(noun (cdr list))
)
(begin
(display "Not an Article!!!")
(display (car list)))
))
And here we see this:
(if ...
...
(begin
(display "Not an Article!!!")
(display (car list))))
The construct begin returns the value of the last expression. Here (display ...) returns void.
Checking the output, we see right before the error message:
Not an Article!!!the
So the problem is that article returns something other than a list.
However since you have found an error, I suggest you look into the function error. Something like: (error 'article (~a "Not an article, got: " (car list)). If you use error DrRacket will directly show you that an error has been found in article.

Illegal argument in functor position - possible bracket issue

I am new to LISP and am trying to develop a few applications. Here I am trying to count the number of occurrences of every element in a list passed to this function. But unfortunately I am getting a " Illegal argument in functor position" error. Can somebody help me solve this and get this program working? Any help would be appreciated
(defun length1 (lst)
(let ((list1 (remove-duplicates lst)))
(cond ((null list1) 0)
(let ((number (count (car list1) lst))))
(print "Word was: ")
(print '(car list1))
(print "Number of Occurances: ")
(print number)
(length (rest lst)))))
In Common Lisp syntax (which appears to be the one used, not Scheme's) this is how it would look:
(defun length1 (lst)
(let ((list1 (remove-duplicates lst)))
(cond ((null list1) 0)
(t (let ((number (count (car list1) lst)))
(print "Word was: ")
(print (car list1))
(print "Number of Occurrences: ")
(print number)
(length (rest lst)))))))

Scheme syntax error when recursing

I'm writing a recursive function that will convert an expression from prefix to infix. However, I need to add in a check to make sure part of the input is not already in infix.
For example, I may get input like (+ (1 + 2) 3).
I want to change this to ((1 + 2) + 3)
Here is what I have so far:
(define (finalizePrefixToInfix lst)
;Convert a given s-expression to infix notation
(define operand (car lst))
(define operator1 (cadr lst))
(define operator2 (caddr lst))
(display lst)
(cond
((and (list? lst) (symbol? operand));Is the s-expression a list?
;It was a list. Recusively call the operands of the list and return in infix format
(display "recursing")
(list (finalizePrefixToInfix operator1) operand (finalizePrefixToInfix operator2))
)
(else (display "not recursing") lst);It was not a list. We can not reformat, so return.
)
)
However, this is giving me syntax errors but I cant figure out why. Any help?
You have to check to see if the lst parameter is a list at the very beginning (base case), otherwise car and friends will fail when applied to an atom. Try this:
(define (finalizePrefixToInfix lst)
(cond ((not (pair? lst)) lst)
(else
(define operand (car lst))
(define operator1 (cadr lst))
(define operator2 (caddr lst))
(cond
((symbol? operand)
(list (finalizePrefixToInfix operator1)
operand
(finalizePrefixToInfix operator2)))
(else lst)))))

Recursion through nested lists in LISP

I am trying to find the other element in the nested list when querying the first one. Something like this. (findOther 'a '((a b) (b c) (a d)))--> b and d. I have done this so far: The problem is I only get b.
(defun findOther (elem L)
(cond (NIL (null L))
((eq elem (caar L)) (cdar L))
((findOther elem (cdr L)))))
First some comments on the original code:
(defun findOther (elem L)
(cond
;; NIL is always false, so you *never* end up using this
;; case. You probably want something like ((null l) '()),
;; NULL is still pretty common for this, but since you're
;; expecting a list, you could use the slighly more
;; descriptive ENDP.
(NIL (null L))
;; When you find an element, you immediately return its
;; counterpart, and don't collect it and continue on to
;; the rest of the list. It's also easier to read if
;; you use more descriptive names like FIRST and SECOND,
;; as in ((eq elem (first (first l))) (second (first l))).
;; It's worth noting that unless you have a specific reason
;; to use EQ, you might want to use EQL, which is the
;; default comparison in most CL functions.
((eq elem (caar L)) (cdar L))
;; Else, you continue to the rest of the list. In my
;; opinion, REST would be more decriptive than CDR here,
;; but recursing and returning the value *is* what you
;; want to do here.
((findOther elem (cdr L)))))
Taking some of those into consideration, we could do something like this:
(defun others (element list)
(cond
((endp list) '())
((eql element (first (first list)))
(list* (second (first list))
(others element (rest list))))
((others element (rest list)))))
All that said, the functions in the standard library
would make this much easier. E.g. using mapcan:
(defun others (element list)
(mapcan (lambda (sublist)
(when (eql (first sublist) element)
(rest sublist)))
list))
(others 'a '((a b) (b c) (a d)))
;=> (B D)
I am not sure if you are looking for pair of two elements or may be more elements in list as well. Just in case you have more elements and you want all of them as well and also of some of them are not really pairs,
(defun pair-of (elem lis)
(let ((temp nil))
(cond
((and (listp lis) (not (null lis)))
(mapcar
#'(lambda (x)
(cond
((and (listp x) (not (null x)) (eql elem (car x)))
(push (cdr x) temp))))
lis)))
(nreverse temp)))
USAGE:(pair-of 'a '((a b) (b c) (a d w) 1))
OUTPUT: ((B) (D W))
But in case you want them combined in one list,
(reduce #'append (pair-of 'a '((a s) (a 3 8) (2 5 1))):initial-value '())
=> (S 3 8)

How to remove a given symbol from a list?

I am trying to remove a given symbol from a list.
Here is the code i wrote:
(define member?
(lambda (in-sym in-seq)
(if (and (symbol? in-sym) (sequence? in-seq))
(if (null? in-seq)
'()
(append
(if (equal? in-sym (car in-seq)) '() (list (car in-seq)))
(member? in-sym (cdr in-seq)))))))
It turns out that i remove all occurences of the given symbol although i want to remove only the first occurence. Can somebody help me with this?
You can use a built-in procedure for this, check if your interpreter provides remove:
(remove 'b '(a b b c b))
=> '(a b c b)
Now, if you intend to implement the functionality yourself, I advice you to split the problem in two parts: one procedure that checks if the procedure can be executed (if inSymbol is a symbol and inSeq is a sequence), and the other, remove-member that performs the actual removal of data:
(define member?
(lambda (inSym inSeq)
(if (and (symbol? inSym) (sequence? inSeq)) ; can remove?
(remove-member inSym inSeq) ; then remove!
'can-not-remove))) ; otherwise, present an error message
(define remove-member
(lambda (inSym inSeq)
(cond ((null? inSeq)
'())
((equal? (car inSeq) inSym)
(cdr inSeq))
(else
(cons (car inSeq)
(remove-member inSym (cdr inSeq)))))))
Your problem is that you append to ( member? inSym ( cdr inSeq)) whether you found the symbol or not. What you want to do is this:
(define member?
(lambda (inSym inSeq)
(if (and (symbol? inSym) (sequence? inSeq))
(if (null? inSeq) '()
(if (equal? inSym (car inSeq)) (cdr inSeq)
(append (list (car inSec)) (member? inSym (cdr inSeq)))
)
)
)
)
)
I.e. if you found the symbol, just return (cdr inSeq) instead because you are done.

Resources