How do I compare the symbol a with the character a? - scheme

I have a list containing letters.
When I do (car '(a)) it gives me the symbol a.
How do I compare it to the character a?
Must I do (eq? (car list) (car '(a))?

Symbols and characters are different kinds of data. Fortunately, Scheme is willing to let you convert nearly anything you want. In Racket, for instance:
#lang racket
;; the symbol a:
'a
;; the character a:
#\a
;; are they equal? no.
(equal? 'a #\a) ;; produces #f
;; converting a character to a symbol:
(define (char->symbol ch)
(string->symbol (string ch)))
(char->symbol #\a) ;;=> produces 'a
;; converting a symbol to a character
(define (symbol->char sym)
(match (string->list (symbol->string sym))
[(list ch) ch]
[other (error 'symbol->char
"expected a one-character symbol, got: ~s" sym)]))
(symbol->char 'a) ;; => produces #\a
With all that said, if you're working on a homework assignment, the instructor almost certainly has an easier path in mind for you.

Related

Just eval first symbol (CHICKEN Scheme)

How can I evaluate an s-expression only by the first term?
(define (fn x y) (print x) (print y))
(eval '(fn a b))
I am trying to evaluate something like this on a bigger expression but the interpreter is complaining that a and b variables don't exist (unbound variable a).
Is there something I can do to leave symbols as they are?
I have been trying to find information about this but I can't find it anywhere.
How about the following?
(let ((expr '(fn a b)))
(cons (eval (car expr)) (cdr expr)))
But please note that if you have to rely on eval, you're almost certainly doing things wrong.

Error in case construct with string comparison (scheme)

(define aaa ;;val:string
(lambda(x) ;;x:string
(case
((string=? (substring x 0 1) "+") (aaa(substring x 1)))
((string=? "a" "b")(string-append("-" (aaa(substring x 1)))))
((char=?(string-ref x 0)#\.) (-404))
(else
(if (= (findpoint x) -1)
"a"
"b"
)
)
)
)
)
Hello, I have a problem with DrRacket:
When I try to run this code, it gives me the error:
case: expected a symbol (without its quote) or a number as a choice, but found a string
referring to the line (5):
((string=? "a" "b")(string-append("-" (aaa(substring x 1)))))
This line was actually supposed to look like this,
((string=? (substring x 0 1) "+")(string-append("-" (aaa(substring x 1)))))
but I thought that using two strings "a" "b" would ease to spot the problem.
I don't understand why i get this error, since both "a" "b" are strings and not symbols or lists, and also I can't understand why I don't get this error on the previous line
CONTEXT:
the procedure is supposed check if the first character of a string is a +/-/., and then do thing through recursion using else (again, "a" "b" are examples)
It seems like you are mixing cond, the flat if-elseif-else, and case, which is similar to a switch statement.
How to use cond:
(cond ((equal? 1 2) 'consequent)
((odd? 1) 'consequent2) ; as many terms as you want. It stops at the first true
(else 'alternative)) ; or else it evaluates the alterntaive
; ==> consequent2
Vs how to use case
(case 'value4
((value1 value2) 'consequent)
((value3 value4) 'consequent2)
(else 'default))
; ==> consequent2
Now that case statement is just sugar. Your Scheme implementation will make it into something similar to this:
(cond ((and (eqv? 'value4 'value1) (eqv? 'value4 'value2)) 'consequent)
((and (eqv? 'value4 'value3) (eqv? 'value4 'value4)) 'consequent2)
(else 'default))
Thus notice the values to match in a case are treated as if they are quoted. Eg. you values can not be variables since they will only match their symbol.
If you want to use case I would have done this:
(define (first-letter-operator? str)
(case (string-ref str 0)
((#\+ #\- #\.) #t)
(else #f)))
(first-letter-operator? "+345634") ; ==> #t
(first-letter-operator? "hello") ; ==> #f

Macro of [S:N] for in-range in Racket

How can I create a macro so that S:N or [S:N] returns a range of numbers starting with S and ending with N (step 1). Basically, it should be able to use it in place of 'in-range'. I tried to create something similar to Curly brackets {} to replace 'begin' in Racket but could not.
Edit: I tried following as suggested by #soegaard :
my-top.rkt:
#lang racket
(define-syntax-rule (my-top S:N)
(range S N) )
(provide (rename-out [my-top #%top]))
test.rkt:
#lang racket
(require "my-top.rkt")
(1:42)
But it does not run. The error is:
#%top: use does not match pattern: (#%top S:N) in: (#%top . 1:42)
[1:42] and 1:42 also do not work.
Here are the steps to make S:N expand to (range S N) where S and N are numbers.
Note that S:N is an identifier. Therefore an unbound S:N is an unbound identifier. An reference to an unbound identifiers n expand to (#%top . n).
Therefore 1:42 expands into (#%top 1:42).
Make a macro my-top such that (my-top S:N) expands to (range S N).
Save your macro in file my-top.rkt and export it using (provide (rename-out [my-top #%top])).
Use your new construct like this:
.
#lang racket
(require "my-top.rkt")
1:42
Step 1:
#lang racket
(require syntax/parse (for-syntax racket/match syntax/parse))
(begin-for-syntax
; contains-colon? : string -> boolean
; does the string str contain a colon?
(define (contains-colon? str)
(regexp-match ".*:.*" str))
; split-colon-string-into-numbers : string -> (list number number)
; for a string of the form N:S return a list consisting of the
; numbers corresponsing to the substrings N and S
(define (split-colon-string-into-numbers str)
(match (regexp-match "(.*):(.*)" str)
[(list _ S-str N-str)
(list (string->number S-str) (string->number N-str))]
[_else
(error 'split-colon-string-into-numbers
"expected string of the number <number>:<number>")])))
; SYNTAX (my-top . id)
; (my-top . id) behaves the same as (#%top . id)
; except when id has the form N:S in which case
; (my-top . id) behaves as (range N S)
(define-syntax (my-top stx)
(syntax-parse stx
[(_my-top . identifier:id)
(define str (symbol->string (syntax-e #'identifier)))
(cond
[(contains-colon? str)
(with-syntax ([(S N) (split-colon-string-into-numbers str)])
(syntax/loc stx
(range S N)))]
[else
#'(#%top . identifier)])]))
;;; Tests
(my-top . 1:5) ; evaluates to (1 2 3 4)
(define foo 42)
(my-top . foo) ; evaluates to 42
#soegaard's answer provided a #%top-based solution which expands S:N when S and N are literal integers and S:N isn't defined as an identifier. However, it's also possible to do this with a reader macro.
I've made two versions: a simple version that only works with literal integers, and another version that works with arbitrary expressions, including variables.
The literal-integer version
This simple version overrides [ to begin range expressions like [S:N], where S and N are literal integers. After the [, it reads numeric characters until it finds a :, then it reads more numeric characters until it finds a ]. It converts the strings of numeric characters into integers, and puts those integers into a list representing a call to the range function.
It would be used like this:
#lang colon-range
;; simple range by itself
[1:42]
;; using a range within a more complicated expression
(for/list ((i [2:42])
#:when
(for/and ((j [2:41]) #:when (< j i))
(not (= 0 (remainder i j)))))
i)
Note that I'm using ((i ....)) instead of the more common ([i ....]) because I can't use [ and ] normally any more.
To implement the #lang colon-range language, you should put the reader implementation in colon-range/lang/reader.rkt, where colon-range is installed as a single-collection package.
;; s-exp syntax/module-reader is a language for defining new languages.
#lang s-exp syntax/module-reader
racket
#:wrapper1 (lambda (th)
(parameterize ([current-readtable
(make-colon-range-readtable (current-readtable))])
(th)))
;; This extends the orig-readtable with an entry for `[` to convert
;; `[1:42]` to `(range 1 42)`. In this simplistic implementation, they
;; have to be literal numbers, so it can't refer to a variable.
(define (make-colon-range-readtable orig-readtable)
(make-readtable orig-readtable
#\[ 'terminating-macro colon-range-proc))
;; This is the function that the new readtable will use when in encounters a `[`
(define (colon-range-proc char in src ln col pos)
(define S (read-int-until #\: in src))
(define N (read-int-until #\] in src))
(list 'range S N))
;; This reads until it finds the given char (consuming it),
;; and returns an exact integer
(define (read-int-until char in src)
(define str (list->string (read-numeric-chars-until char in src)))
(define i (string->number str))
(unless (exact-integer? i)
(error 'read "expected an exact integer, given `~a`" str))
i)
;; This reads until it finds the given char (consuming it), and returns a list
;; of characters. Each char it reads before that needs to be a numeric char,
;; otherwise it throws an error.
(define (read-numeric-chars-until char in src)
(define c (read-char in))
(cond [(eof-object? c)
(error 'read "end-of-file: expected either a number or a `~a`, given `~a`"
char c)]
[(char=? char c)
(list)]
[(char-numeric? c)
(cons c (read-numeric-chars-until char in src))]
[else
(error 'read "expected either a number or a `~a`, given `~a`"
char c)]))
The arbitrary-expression version
This version overrides both [ and :. It defines : as a separator so that a:b reads the same as a : b, and it defines [ as a reader macro that reads a normal list and processes it afterwards. So it will first take [a : b] as a list of three elements, and then translate it to (range a b).
It can be used like this:
#lang colon-range
;; simple range by itself
[1:42]
;; using a range within a more complicated expression
(for/list ([i [2:42]]
#:when
(for/and ([j [2:i]]) ; can refer to a variable
(not (= 0 (remainder i j)))))
i)
(define two 2)
(for/list ([i [two:42]] ; can refer to a variable for the start
#:when
(for/and ([j [two:(+ 1 (exact-floor (sqrt i)))]]) ; can use arbitrary expressions
(not (= 0 (remainder i j)))))
i)
The implementation looks like this (again in colon-range/lang/reader.rkt). The comments explain some of what it's doing.
;; s-exp syntax/module-reader is a language for defining new languages.
#lang s-exp syntax/module-reader
racket
#:wrapper1 (lambda (th)
(parameterize ([current-readtable
(make-colon-range-readtable (current-readtable))])
(th)))
;; This extends the orig-readtable with entries for `[` and `:` to convert
;; `[S:N]` to `(range S N)`.
(define (make-colon-range-readtable orig-readtable)
(make-readtable orig-readtable
#\[ 'terminating-macro colon-range-proc
#\: 'terminating-macro separator-proc))
;; This is the function that the new readtable will use when in encounters a `[`
(define (colon-range-proc char in src ln col pos)
;; This reads the list of things ending with the character that closes `char`
;; The #f means it uses the racket reader for the first step, so that `[`
;; uses the normal behavior, grouping expressions into a reader-level list
(define lst (read-syntax/recursive src in char #f))
;; This matches on that list to determine whether it has the shape `[S : N]`
(syntax-case lst (:)
[[S : N]
;; if it is, translate it to `(range S N)`
(list 'range #'S #'N)]
[_
;; otherwise leave it alone
lst]))
;; This doesn't read any further and simply returns an identifier containing char,
;; so that it can act like a separator
(define (separator-proc char in src ln col pos)
(char->identifier char (list src ln col pos 1)))
(define (char->identifier char srcloc)
(datum->syntax #f (string->symbol (string char)) srcloc))

Removing/comparing string value with a list - scheme

I am trying to remove members which exists in a string from a list consisting of those members.
Example:
String: "ABC"
List: ('A 'B 'C 'D)
To do: Remove first element of string from the list
To remove the the element from the string:
I am converting it to a list using:
(car (string->list"ABC")
This gives me character list and first element: #\A
But I do not get how I can remove it from the list as both values do not compare: the character and list values.
Tried this weird approach which did not work:
((eq? (make-string 1 (car (string->list"ABC"))) (car (list 'A 'B 'C 'D))))
Does not work as string value does not compare with the first list value.
How I can compare & remove the first string alphabet from the original list??
Error as list cannot have string element values:
This is not true. A list can have strings as well as characters as its elements, no problem. You're getting the error because you're using car on a string, not a list.
(car (list->string(list(car (string->list "ABC")))))
Ok, here you're calling (string->list "ABC") which gives you a list containing the character A, B and C. Now you're calling car on that and get the character A back. Up to here there's no problem.
But then you're calling list on that character getting a list which only contains the character A and then use list-string to turn this into the string "A". This is still perfectly legal. But then you're calling car on the string "A" and that's the error because you're calling car on a string, but car only accepts a list (well, any pair actually) as its argument.
Since you're trying to compare A against that first element of ('A 'B 'C 'D), i.e. 'A, which is a symbol, you probably want to convert the string "A" into the symbol 'A (or the symbol 'A into the string "A"). To do this, you can use the function string->symbol instead of car.
Once you have the symbol A, you can easily remove it from the list using the filter function:
(let ((a (string->symbol (list->string (list (car (string->list "ABC")))))))
(filter (lambda (x) (not (eq? x a))) '(A B C)))
Something like this:
(define lst '(#\a #\b #\c #\d))
(define str (string->list "abc"))
(define (reduce-list lst str)
(cond
[(empty? str) lst]
[else (reduce-list (remove (first str) lst) (rest str))]
)
)
(reduce-list lst str)
Result:
(list #\d)

Call to defmacro with a quoted symbol

I have this data structure (basically):
(setq ssm-list '(tasklist
((id . "10525295")
(name . "Inbox")
(sort_order . "0"))))
This works for getting the name:
(defun ssm-list-get-prop (list prop)
(cdr (assoc prop (car (cdr list)))))
(ssm-list-get-prop slack-one-list 'name)
What'd I like is to create a macro that will create a defun with the name ssm-list-name (or ssm-list-id) as there are actually a lot more properties in the list.
So I tried this:
(defmacro ssm-list-prop-defun (field)
`(defun ,(intern (concat "ssm-list-" field))
(one-list)
(cdr (assoc ,field (car (cdr one-list))))))
(ssm-list-prop-defun 'name)
(ssm-list-prop-defun 'id)
But the last two calls failed miserably with (wrong-type-argument characterp quote) I tried putting symbol-name in the macro but that didn't help.
Is there a way to accomplish this?
You're very close, minor edits gets you a working solution. The problem is that you're mixing symbols and strings. This will work:
(defmacro ssm-list-prop-defun (field)
;; note that concat operates on strings
`(defun ,(intern (concat "ssm-list-" field))
(one-list)
;; note that you need a symbol here, so quote the
;; result of the call to intern
;; and, if you're always using symbols,
;; might as well use assq
(cdr (assq ',(intern field) (car (cdr one-list))))))
;; pass in a string
(ssm-list-prop-defun "name")
And here's the variant that uses a symbol:
;; variant that works off a symbol
(defmacro ssm-list-prop-defun (field)
`(defun ,(intern (concat "ssm-list-" (symbol-name field)))
(one-list)
(cdr (assq ',field (car (cdr one-list))))))
(ssm-list-prop-defun name)
I think you want to read about defstruct in the cl package: (info "(cl) Structures") (or http://www.gnu.org/software/emacs/manual/html_node/cl/Structures.html#Structures)

Resources