I'm trying to interpret a list of keywords and integers to obtain an expression. If "input" is, say '(add 5 5), the incoming list would contain 3 pieces -> add 5 5
(define (evaluate input)
(if (integer? input)
input
(cond ((integer? (car input))
(car input))
((equal? (car input) "add")
(+ (evaluate (cdr input))
(evaluate (cddr input))))
~more~
I'm using the 'if' because cond doesn't like just returning a value. My questions are: Does equal? actually compare strings properly and should the (+ evaluate (...) evaluate(...)) actually return 10 in this case?
In the last line,
(+ (evaluate (cdr input)) (evaluate (cddr input))))
has to be
(+ (evaluate (cadr input)) (evaluate (caddr input))))
Because in the if-comparison, it has to return directly the number. But of course, instead you can also use cond, you dont have to use a other comparison methode.
To compare strings, you can use best string=? function.
More info:
add is actually a Scheme symbol, not a string, so you can just use eq?:
(define (evaluate input)
(cond
[(integer? input)
input]
[(integer? (car input))
(car input)]
[(eq? 'add (car input))
(+ (evaluate (cadr input) (caddr input)))]))
BTW, it looks like what you're really trying to do is "destructure" the input when it matches a pattern: that is, extract stuff that's stored inside the input. There's a nice little macro by Oleg Kiselyov called pmatch that does this for you. Download it from http://www.cs.indiana.edu/cgi-pub/c311/lib/exe/fetch.php?media=pmatch.scm . Then you can write the following, which handles all that cdr/cadr/caddr/etc. stuff automatically, and supports any number of arguments to add, and doesn't need the case where an integer is enclosed alone in parentheses:
(define (evaluate input)
(pmatch input
[,n (guard (integer? n))
n]
[(add . ,operands)
(apply + (map evaluate operands))]))
pmatch expects a series of clauses, like cond, except the first expression in the clause is a pattern, which can contain variables. The variables are indicated by preceding them with a comma (just as in a backquote expression). Any symbols in a pattern that aren't preceded by a comma must match literally. When pmatch finds a matching pattern, it binds the variables to the parts of the input that are in the corresponding parts of the input. n and operands are variables in the patterns above.
You can also stick a guard clause after a pattern if you want to require a condition beyond just matching the pattern, like checking if the extracted variable is an integer.
Related
I'm trying to make a terminal parser (for a parser combinator) from scratch. My approach is to use regexp-match-positions* on the input string and if the pattern is found at the first position, then we output the split string.
This is what I've got, so far:
#lang racket/base
(require racket/match)
(define (make-terminal-parser pattern)
(define (regexp-match-from-start pattern input)
(match (regexp-match-positions* pattern input)
[(list (cons 0 x) ...)
(let ([index (car x)])
(values (substring input 0 index)
(substring input index)))]
[_ (error "Not found!")]))
(lambda (input)
(regexp-match-from-start pattern input)))
(define ALPHA (make-terminal-parser #rx"[a-zA-Z]"))
(ALPHA "hello")
My ALPHA doesn't seem to work and I think it's because of the pattern matching not equating with anything. In the REPL, (regexp-match-positions* #rx"[a-zA-Z]" "hello") outputs what I would expect ('((0 . 1) (1 . 2) etc.)), so I don't really understand why that doesn't match with (list (cons 0 x) ...). If I change the regular expression to #rx"h", then it correctly splits the string; but obviously this is too specific.
(On a related note: I don't understand why I need to (car x) to get the actual index value out of the matched cons.)
It turns out the problem I was having was indeed with my pattern matching. I was attempting to match on (list (cons 0 x) ...), but the documentation implies that will only match a list of one-or-more elements of (0 . x) (where x is arbitrary). That's not what I want.
Lists are a series of cons, so I changed my matching criteria to (cons (cons 0 x) _) and that gives me what I want.
That also explains why I had to (car x) in my previous attempt. The x match in (list (cons 0 x) ...) would have matched every righthand element of each cons in the list, so it would have returned a list. For example '((0 . 1) (0 . 2) (0 . 3)) would have matched and x would equal '(1 2 3).
So, my fixed code is:
(define (make-terminal-parser pattern)
(define (regexp-match-from-start pattern input)
(match (regexp-match-positions pattern input)
[(cons (cons 0 index) _)
(values (substring input 0 index)
(substring input index))]
[_ (error "Not found!")]))
(lambda (input)
(regexp-match-from-start pattern input)))
n.b., I also don't need to use the starred version of regexp-match-positions with pattern matching, fwiw.
How would you replace the cond to an if else in this program?
#lang racket
(define (my-map f lst)
(cond
[(empty? lst) empty]
[else (cons (f (first lst))
(my-map f (rest lst)))]))
A cond expression with just one condition and a single expression as the consequent and an else part with a single expression as the alternative can be easily transformed into an if expression. For example, this:
(cond (<cond1> <exp1>)
(else <exp2>))
Is equivalent to this:
(if <cond1> ; condition
<exp1> ; consequent
<exp2>) ; alternative
In particular, your code can be rewritten as:
(define (my-map f lst)
(if (empty? lst)
empty
(cons (f (first lst))
(my-map f (rest lst)))))
Also notice that a cond is just a shorter way to express a series of nested if expressions. Think of it as a shorthand for IF-ELSE IF-ELSE IF-ELSE in other programming languages. In fact, for the general case many interpreters implement this:
(cond (<cond1> <exp1> <exp2>) ; we can have any number of conditions
(<cond2> <exp3> <exp4>) ; and any number of expressions after condition
(else <exp5> <exp 6>))
... As a syntactical transformation that (ignoring the => syntax) gets expanded into:
(if <cond1>
(begin
<exp1>
<exp2>)
(if <cond2>
(begin
<exp3>
<exp4>)
(begin ; the last expression is the `else` part
<exp5>
<exp6>)))
Notice that the expressions after each condition are inside a begin form, meaning that in a cond they're implicitly inside a begin - so you can write more than one! whereas in an if expression only a single expression can go in either the consequent or the alternative, and if more than one is needed a begin must be used. As always, refer to the documentation for more details.
Every cond:
(cond (predicate consequent)
(predicate2 consequent2-1 consequent2-2)
(else alternative))
Can be rewritten:
(if predicate
consequent
(if predicate2
(begin
consequent2-1
consequent2-2)
alternative))
Your example becomes particularly simple because there is not more than 2 clauses and the code does not make use of explicit begin.
Racket isn't really Scheme as, for example, Racket requires a different if syntax than Scheme. But, figuring that you are, in fact, learning Scheme you might check out the Scheme R7RS Specification; it provides a definition of cond in terms of if. Here is a definition that I've simplified for you by axing templates involving '=>':
(define-syntax cond
(syntax-rules (else)
((cond (else result1 result2 ...))
(begin result1 result2 ...))
((cond (test)) test)
((cond (test) clause1 clause2 ...)
(let ((temp test))
(if temp temp
(cond clause1 clause2 ...))))
((cond (test result1 result2 ...))
(if test (begin result1 result2 ...)))
((cond (test result1 result2 ...)
clause1 clause2 ...)
(if test
(begin result1 result2 ...)
(cond clause1 clause2 ...)))))
Beautiful, yes?
I am trying to define my own function to make my hw2 easier but it is not working. Could you take a look at it and tell me what I am missing?
(DEFUN testAL(x)
COND ( ( ATOMP(x) ) 'this-is-an-atom )
( ( LISTP(x) ) 'this-is-a-list )
( T 'this-is-neither ) )
I want this conditional function to take an input X and output if it is an atom, list, or neither. Problem is that when I input NIL, I get an error: Attempt to take the value of the unbound variable `COND'.
Homework 2 consists of the following question:
Which of the following are atoms, which lists, which both and witch neither?
a. nil
b. (expt 10 3)
c. (a b)
d. 64
e. T
f. (No place like home)
g. ‘(+ 3 5 6)
Your parenthesis are not in the correct places. A parenthesis, unless quoted, are the start of a function application.
It begins with a variable cond that is not bound. It's not the special form (cond (predicate consequent) (predicate2 consequent2)) since it doesn't start with an open parenthesis.
From indentation alone I guess you meant to write:
(DEFUN testAL (x)
(COND ((ATOM x) 'this-is-an-atom)
((LISTP x) 'this-is-a-list)
(T 'this-is-neither)))
(testal 'test) ; ==> THIS-IS-AN-ATOM
(testal '(a b c)) ; ==> THIS-IS-A-LIST
I have removed the extra parenthesis around x since (x) means apply the function x while x means the variable x. With x in a different position like (+ x 3) then + is the function to be applied and x is one of its operands.
I changed atomp to atom. Since atom is one of the very first primitives defined with the very first LISP in the 50's, it does not have a postfix p like most other predicates.
Edit: Multiple match
You could just have several cond (or if since you only have one test in each) and do side effects like (print "THIS-IS-AN-ATOM") since your base case will never trigger (nothing is neither list nor atom in CL). This is perhaps the easies solution.
(DEFUN testAL (x)
(if (ATOM x) (print 'this-is-an-atom))
(if (LISTP x) (print 'this-is-a-list)))
(testal '()) ; ==> THIS-IS-A-LIST (but prints both)
For a more functional approach I would have done it with higher order functions keeping the code testable and supply a print-function that does the side effects. Be aware that this might not be as easy to read for a beginner:
;; a list of pairs of predicate and their desription
(defparameter *type-predicates-and-description*
'((douglasp . this-is-the-answer-to-everything)
(floatp . this-is-a-floating-pont-number)
(integerp . this-is-an-integer)
(numberp . this-is-a-number)
(null . this-is-null)
(listp . this-is-a-list)
(characterp . this-is-a-character)
(stringp . this-is-a-string)))
;; custom made predicate
(defun douglasp (x)
(and (numberp x) (= x 42)))
;; returns all the types of a particular value
(defun get-type-info (x)
"return a list if types thet describes argument"
(flet ((check-type (acc type-pair)
"Accumulate description when predicate match"
(if (funcall (car type-pair) x)
(cons (cdr type-pair) acc)
acc)))
;; test x for each type predicate-description
(let ((res (reduce #'check-type
*type-predicates-and-description*
:initial-value '())))
;; check of empty list (no types matched)
(if (null res)
(list 'this-is-neither)
res))))
;; test it
(get-type-info '()) ; ==> (THIS-IS-A-LIST THIS-IS-NULL)
(get-type-info 42) ; ==> (THIS-IS-A-NUMBER
; THIS-IS-AN-INTEGER
; THIS-IS-THE-ANSWER-TO-EVERYTHING)
(get-type-info #()) ; ==> (THIS-IS-NEITHER)
;; Make a function to do side effects
(defun print-type-info (x)
(format t "~{~a~^, ~}." (get-type-info x)))
(print-type-info '()) ; ==> NIL
; and prints "THIS-IS-A-LIST, THIS-IS-NULL."
I am trying to write a function using Common Lisp functions only that will count how many s-expressions are in an s-expression. For example:
((x = y)(z = 1)) ;; returns 2
and
((x - y)) ;; returns 1
Nested expressions are possible so:
((if x then (x = y)(z = w))) ;; returns 3
I wrote a function which finds the length and it works if no nested expressions are there. It is:
(define (length exp)
(cond
((null? exp) 0)
(#t (+ 1 (length (cdr exp))))))
Now I modified this in an attempt to support nested expressions to the following:
(define (length exp)
(cond
((null? exp) 0)
((list? (car exp)) (+ 1 (length (cdr exp))))
(#t (length (cdr exp)))))
This works for expressions with no nests, but is always 1 less than the answer for nested expressions. This is because taking the example above, ((if x then (x = y)(z = w))), this will look at if at first and which satisfies the third condition, returning the cdr (the rest of the expression as a list) into length. The same happens up until (x=y) is reached, at which point a +1 is returned. This means that the expression (if x then .... ) has not been counted.
In what ways would I be able to account for it? Adding +2 will over-count un-nested expressions.
I will need this to work in one function as nesting can happen anywhere, so:
((x = y) (if y then (z = w)))
At first sight, your code only recurses to the right (cdr-side) and not to the left (car-side), so that definitely is a problem there.
On second sight, this is even a little bit more tricky than that, because you are not exactly counting conses; you need to differentiate the case where a cons starts a proper list vs where it's the cdr of a list. If you were to recurse to the car and cdr, that information would be lost. We need to iterate over the sexp as a proper list,
(defun count-proper-list (sexp)
(cond ((atom sexp) 0)
(t (1+ (reduce #'+ (mapcar #'count-proper-list sexp))))))
But this will also count the top level list, therefor always return one more than what you seem to want. So perhaps,
(defun count-proper-sublist (sexp)
(1- (count-proper-list sexp)))
I am trying to define a procedure that takes an argument of 2 lists and a non-negative integer. Assume perfect input. I want it to construct a list of the elements in the first list UNTIL it reaches the given integer of elements at which point I want to finish it with the remainder of elements from the second list. Let me demonstrate.
~(combine '(a b c d e) '(w x y z) 2)
(a b y z)
Notice that the second list continued from the next index as if it were being made to cdr the whole time.
This is what I have. It doesn't work, of course and I think I may be using the wrong logic.
(define (combine seq1 seq2 point)
(if (null? (or seq1 seq2))
'()
(if (equal? point 0)
(cons seq2 '())
(cons (car seq1) (combine (cdr seq1) (cdr seq2) (- point 1) )))))
All help would be appreciated!
Thank you!
Well, this line doesn't do what you want:
(if (null? (or seq1 seq2))
In Scheme, the empty list is a true value; the only false value in Scheme is #f. That means that
(or '() '(a))
returns '() but
(or '(a) '())
returns '(a)
So your check for null will return #t only half of the time. (And if '() were a false value, as it is in regular Lisp, then it would never work, so I'm not sure what you are thinking).
If you want that line to return true if either of the lists is null, you will have to rethink it.
Then there's the line
(cons seq2 '())
Try testing that function on its own and see what happens - it's not what you need. If you think about it, that line should be rather simpler. What do you actually need to return at that point?