In scheme - how can I evaluate a simple expression (containing only + * - / () and 0-9 digits) given as a string?
I've tried to first turn the expression into a postfix expression but I guess I'm doing something wrong.
Thank you
Maybe you can use this parser for infix expressions.
http://planet.racket-lang.org/package-source/soegaard/infix.plt/1/0/planet-docs/manual/index.html
Here is a small example (it takes a while for the library to install - it seems the old Schematics test suite takes forever to install these days - I need to switch to a builtin one).
#lang at-exp racket
(require (planet soegaard/infix)
(planet soegaard/infix/parser))
(display (format "1+2*3 is ~a\n" #${1+2*3} ))
(parse-expression #'here (open-input-string "1+2*3"))
The output will be:
1+2*3 is 7
.#<syntax:6:21 (#%infix (+ 1 (* 2 3)))>
The function parse-expression parses the expression in the string and
returns a syntax-object that resembles the output of ToExpression.
Related
I understand that Scheme uses ports to perform Input and Output. While trying to learn how to get console input and output, I have come across MIT-Scheme's console-i/o-port variable.
But, the guile interpreter says it is an Unbound Variable. I would like to know how we can use ports to get input from and output to the console (Terminal in Unix) in a Guile Scheme Script. I am still a rookie in Scheme and Linux, a clear step-by-step is appreciated.
Also, how does (display <object>) work? Does it use ports inherently or is there another way.
P.S. If there is another way without using ports please let me know how to use that too.
If you want to read and write SExps, in guile you have (read), (write), (display) etc., if you want to read characters only use (read-char) and (write-char) -- they all use the input/output ports resp. you picked, by default they are stdin and stdout. Everything is rather straightforward (https://www.gnu.org/software/guile/manual/html_node/Input-and-Output.html#Input-and-Output).
You might also be interested in guile-ncurses (https://www.gnu.org/software/guile-ncurses/).
Of some more goodies check out pretty-print module from ice-9 (on very long sexps it's slow but outputs them really nicely formatted, great for e.g. code generation):
(use-modules (ice-9 pretty-print))
(pretty-print `(super cool stuff (+ 2 3) => ,(+ 2 3)))
And if you need your own parser, check out the lalr module (system base lalr).
edit a small example which reads a number, multiplies by itself and prints out the result:
#!/usr/bin/guile -s
!#
(let ((x (read)))
(display (* x x))
(newline))
(remember to chmod +x this script).
edit changed the expression to let form as Chris suggested, indeed the fewer parentheses the better
In guile you have 2 functions: current-input-port and current-output-port (the docs)
to read and put text into string (if you don't want to read s-expressions) you can use this function:
(define (read-port port)
(let iter ((result '()) (chr (read-char port)))
(if (eof-object? chr)
(list->string result)
(iter (append result (list chr)) (read-char port)))))
reading from stdin will be:
(read-port (current-input-port))
to write to stdout you can use display it also accept second argument which is port relevant docs
I've just been reading up on the sharpsign colon reader macro and it sounded like it had a very similar effect to gensym
Sharpsign Colon: "introduces an uninterned symbol"
Gensym: "Creates and returns a fresh, uninterned symbol"
So a simple test
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {1002FF77D3}>.
CL-USER> (defparameter #:dave 1)
#:DAVE
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {100324B493}>.
Cool so that fails as it should.
Now for the macro test
(defmacro test (x)
(let ((blah '#:jim))
`(let ((,blah ,x))
(print ,blah))))
CL-USER> (test 10)
10
10
CL-USER>
Sweet so it can be used like in a gensym kind of way.
To me this looks cleaner than gensym with an apparently identical result. I'm sure I'm missing a vital detail so my question is, What it it?
Every time the macro is expanded, it will use the same symbol.
(defmacro foo () `(quote #:x))
(defmacro bar () `(quote ,(gensym)))
(eq (foo) (foo)) => t
(eq (bar) (bar)) => nil
Gensym will create a new symbol every time it is evaluated, but sharp colon will only create a new symbol when it is read.
While using sharp colon is unlikely to cause problems, there are a couple rare cases where using it would lead to nearly impossible to find bugs. It is better to be safe to begin with by always using gensym.
If you want to use something like sharp colon, you should look at the defmacro! macro from Let Over Lambda.
GENSYM is like MAKE-SYMBOL. The difference is that GENSYM supports fancy naming by counting up -> thus symbols kind of have unique names, which makes debugging a bit easier when having gensyms for example in macro expansions.
#:foo is a notation for the reader.
So you have a function which creates these and a literal notation. Note that, when *print-circle* is true, some kind of identity maybe preserved in s-expressions: #(#1=#:FOO #1#).
Generally this is similar to (a . b) and (cons 'a 'b), #(a b) and (vector 'a 'b)... One is literal data and the other one is a form which will create ('cons') fresh objects.
If you look at your macro, the main problem is that nested usage of it could cause problems. Both lexically or dynamically.
lexically it could be the same variable, which is rebound.
dynamically, if it is a special variable it could also be rebound
Using a generated symbol at macro expansion time would make sure that different and expanded code would not share bindings.
Why doesn't the following work?
((if t + -) 1 1)
How can I get the if expression to resolve to provide the correct function? I don't want to repeat myself, as in (if t (+ 1 1) (- 1 1)).
Emacs Lisp is a Lisp-2, meaning it has a separate namespace for functions. To refer to a function as a value in Emacs Lisp, you need to quote it. And to call a function referenced in this way, you need to use funcall. So what you want is:
(funcall (if t '+ '-) 1 1)
Basically what I am trying to do with this is alter the reader so that it will accept vector notation like i+j+k. The goal of this is to convert things that look like vectors into strings while not affecting anything else. For instance, if someone typed in abc it would still throw an error message, but if someone typed in i+j+k would return "i+j+k".
This is what I have so far:
#lang racket/base
(require syntax/strip-context)
(provide (except-out (all-from-out racket/base)
#%top)
(rename-out (#%my-top #%top)))
(require (for-syntax racket/base))
(define-syntax (#%my-top stx)
(syntax-case stx ()
[(_ . quat)
#' (test (#%datum . quat))]
[(_ . other)
(syntax/loc stx
(#%datum . other))]))
(define (quat? testExp)
(regexp-match-exact? #rx"([+-]?([0-9]+[i-k]?|[0-9]*[i-k])([+-]([0-9]+[i-k]?|[0-9]*[i-k]))*)" testExp))
(define (test x)
(cond ((quat? (symbol->string x)) (symbol->string x))
(else (strip-context x))))
This code does work in converting vector notation into strings. i+j+k successfully becomes "i+j+k". But the problem is that it converts EVERYTHING into syntax first, and I cannot get it back to whatever it originally was. For example, abc will become 'abc and it wont throw an error like it normally should. I have no idea how to get around this. I originally thought all I needed was a simple change to that else statement on the final line, but I cannot get anything to work. I am beginning to think I need to try a completely new approach. Any help would be greatly appreciated.
Also, it should be noted that you have to have this code in one file, I called mine parse.rkt, and perform your tests in a separate file that only has
#lang racket
(require "parse.rkt")
I've a database which returns vaild CL expressions within double quotes.
Is it possible to convert these strings to expressions.
For example, I make a query from this DB via CLSQL and as a result it returns me:
"(foo a b)"
How should I convert this expression to:
(foo a b)
and further evaluate it?
> (read-from-string "(foo a b)")
(FOO A B) ;
9
The 9 is the second of multiple values produced by read-from-string; you can ignore it:
(eval (read-from-string "(foo a b)"))
will do what you want given the proper definitions.
* (read-from-string "(+ 1 2)")
(+ 1 2)
7
There is a security problem. See the variable *read-eval*.
* (read-from-string "#.(+ 1 2)")
3
9
You really need to make sure that *read-eval* is NIL, so that reading will not evaluate code.
* (let ((*read-eval* nil)) (read-from-string "#.(+ 1 2)"))
debugger invoked on a SB-INT:SIMPLE-READER-ERROR:
can't read #. while *READ-EVAL* is NIL
Additionally calling EVAL on arbitrary input from a database is not a good idea.
Usually you want to make sure that the code does only call allowed functions.