In python objects, overriding the methods __repr__ and __str__ of an object allows one to provide "unambiguous" and "human-readable" representations of the object, respectively. How does one achieve similar behavior in Racket?
I came across the printable<%> interface here, which seems like it should be usable for this purpose, but I haven't been able to get it to work quite as I expect it to. Building on the standard "fish" example from the docs:
(define fish%
(class* object% (printable<%>)
(init size) ; initialization argument
(super-new) ; superclass initialization
;; Field
(define current-size size)
;; Public methods
(define/public (get-size)
current-size)
(define/public (grow amt)
(set! current-size (+ amt current-size)))
(define/public (eat other-fish)
(grow (send other-fish get-size)))
;; implement printable interface
(define/public (custom-print port quoting-depth)
(print "Print called!"))
(define/public (custom-write port)
(print "Write called!"))
(define/public (custom-display port)
(print "Display called!"))))
This is the output I get:
> (define f (new fish% [size 10]))
> f
"Display called!""Display called!""Print called!"
> (print f)
"Write called!""Print called!"
> (display f)
"Display called!""Display called!"
> (write f)
"Write called!""Write called!"
>
So the question is threefold:
Why does it behave this way, i.e. with the multiple methods being invoked on an apparently singular rendering of the object?
What should the methods custom-print, custom-write, and custom-display evaluate to? Should they simply return a string, or should they actually entail the side effect of printing, writing, or displaying, as the case may be? E.g. should the custom-write method invoke the write function internally?
Is this the right construct to use for this purpose at all? If not, is there one / what is it?
As for
Why does it behave this way, i.e. with the multiple methods being invoked on an apparently singular rendering of the object?
You have accidently used print in write, so writing the value, will first print the value.
(define/public (custom-write port)
(print "Write called!"))
A similar problem is present in display.
Also remember to print/write/display to the proper port.
Try
#lang racket
(define fish%
(class* object% (printable<%>)
(init size) ; initialization argument
(super-new) ; superclass initialization
;; Field
(define current-size size)
;; Public methods
(define/public (get-size)
current-size)
(define/public (grow amt)
(set! current-size (+ amt current-size)))
(define/public (eat other-fish)
(grow (send other-fish get-size)))
;; implement printable interface
(define/public (custom-print port quoting-depth)
(print (~a "Print " current-size "\n") port))
(define/public (custom-write port)
(write (~a "Write " current-size "\n") port))
(define/public (custom-display port)
(display (~a "Display " current-size "\n") port))))
In the repl you will see:
> (define f (new fish% [size 10]))
> f
"Print 10\n"
> (display f)
Display 10
> (write f)
"Write 10\n"
Another answer has already helped you find the problem in your code—you need to use the port given as an argument, not the implicit (current-output-port)—but the explanation isn't quite right. To tackle your questions in reverse order:
Is this the right construct to use for this purpose at all? If not, is there one / what is it?
Yes, printable<%> is the right construct to use to customize printing of a class-based object. More generally, a struct type that is not a class can customize printing for instance through the gen:custom-write generic interface or the low-level prop:custom-write struct type property, which is used to implement printable<%>.
What should the methods custom-print, custom-write, and custom-display evaluate to? Should they simply return a string, or should they actually entail the side effect of printing, writing, or displaying, as the case may be? E.g. should the custom-write method invoke the write function internally?
The methods should actually do the side-effect of performing IO on the port they are given as an argument. They should use the corresponding function (e.g. write for custom-write, print for custom-print) internally for recursively printing/writing/displaying values in fields. On the other hand, when directly emitting particular characters, they should generally use functions like write-char, write-string, or printf. The docs for gen:custom-write give an example of a tuple datatype that prints as <1, 2, "a">: it uses write-string for the angle-brackets and commas, but recursive print/write/display for the elements of the tuple.
Why does it behave this way, i.e. with the multiple methods being invoked on an apparently singular rendering of the object?
This is the most involved part of your question. Printing in Racket is customizable through several hooks: for a few examples, see current-print, port-write-handler, global-port-print-handler, and make-tentative-pretty-print-output-port. Many of these customization hooks use intermediate ports in the process of producing output.
One thing that is not a part of the explanation is the fact that you used print in your implementation, particularly as print is bound to the normal Racket function by lexical scope, not to a method of your object.
As an illustration, consider the following adaptation of your example, which reports to the (current-output-port) the identity of the port given as an argument to the method:
#lang racket
(define report
(let ([next-id 0]
[id-cache (make-hash)])
(λ (op port)
(printf "~a ~a ~v\n"
op
(hash-ref id-cache
port
(λ ()
(define id next-id)
(hash-set! id-cache port id)
(set! next-id (add1 next-id))
id))
port))))
(define fish%
(class* object% (printable<%>)
(super-new)
;; implement printable interface
(define/public (custom-print port quoting-depth)
(report "custom-print " port))
(define/public (custom-write port)
(report "custom-write " port))
(define/public (custom-display port)
(report "custom-display" port))))
(define f (new fish%))
f
(print f)
(newline)
(display f)
(newline)
(write f)
In DrRacket, this generates the output:
custom-display 0 #<output-port:null>
custom-display 1 #<output-port:null>
custom-print 2 #<printing-port>
custom-display 3 #<output-port:null>
custom-display 4 #<output-port:null>
custom-print 5 #<printing-port>
custom-display 6 #<output-port:null>
custom-display 7 #<printing-port>
custom-display 8 #<output-port:null>
custom-write 9 #<printing-port>
while at the command line, the output is:
$ racket demo.rkt
custom-write 0 #<output-port:null>
custom-print 1 #<output-port:redirect>
custom-write 2 #<output-port:null>
custom-print 3 #<output-port:redirect>
custom-display 4 #<output-port:null>
custom-display 5 #<output-port:redirect>
custom-write 6 #<output-port:null>
custom-write 7 #<output-port:redirect>
Related
I am very new to working with Racket. I need my interpreter to correctly identify the following statement and execute the "while" loop.
(= x 10)
(while (> x 0) ((print x)(= x (- x 1))))))
Currently, my implementation of a while loop is throwing an error I don't entirely understand.
My partial implementation is as follows:
(define interp
(lambda (stmt myEnv)
(cond
((eqv? (car stmt) 'print) (begin
(display "\n")
(display (exp myEnv (cadr stmt)))
myEnv))
((eqv? (car stmt) '=) (extend-env myEnv (cadr stmt)(exp myEnv (caddr stmt))))
((eqv? (car stmt) 'while) (while myEnv (cadr stmt)))
(define (while cond body)
(when (cond)
(display "x")
(while cond body)))
I'm getting an error that says:
application: not a procedure;
expected a procedure that can be applied to arguments
given: '(extend-env x 10 (empty-env))
Which leads me to believe I am fatally misunderstanding a key component of how Racket processes functions. Could someone explain what my misstep may be, and how I could go about fixing this definition? A large portion of this skeleton code has been provided for me, so if possible I would like to get the while definition working without modifying anything other than the while definition and the line where I am passing the variables and calling the while definition.
I have been creating some PCB footprints in KiCad recently, which are stored in s-expression files with data that looks like this:
(fp_text user %R (at 0 5.08) (layer F.Fab)
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_line (start -27.04996 -3.986) (end -27.24996 -3.786) (layer F.Fab) (width 0.1))
(pad "" np_thru_hole circle (at 35.56 0) (size 3.175 3.175) (drill 3.175) (layers *.Cu *.Mask)
(clearance 1.5875))
(pad 96 smd rect (at 1.25 3.08473) (size 0.29972 1.45034) (layers F.Cu F.Paste F.Mask)
(clearance 0.09906))
I would like to be able to write shell one-liners to efficiently edit multiple parameters. I would normally use Awk for something like this, but the recursive nature of s-expressions makes it ill-suited for the task. I would like to know if there is a programming language with an interpreter designed to handle piped data and can process s-expressions natively. Perhaps a data-driven dialect of Lisp would do this, but I'm not sure where to look.
In summary, I would like to be able to make quick edits to an s-expression file in a similar manner to the way Awk lets me process columns of data line-by-line; only in the case of s-expressions the processing would be performed level-by-level.
Example: find all of the pad expressions of type smd with (size 0.29972 1.45034), and renumber each one based its position.
Simple script
Here is an example in Common Lisp, assuming your input is in file "/tmp/ex.cad" (it could also be obtained by reading the output stream of a process).
The main processing loop consists in opening the file in order to obtain an input stream in (which is automatically closed at the end of with-open-file), loop over all forms in the file, process them and possibly output them to standard output. You could complexify the process as much as you want, but the following is good enough:
(with-open-file (in #"/tmp/ex.cad")
(let ((*read-eval* nil))
(ignore-errors
(loop (process-form (read in))))))
Suppose you want to increase the width of fp_line entries, ignore fp_text and otherwise print the form unmodified, you could define process-form as follows:
(defun process-form (form)
(destructuring-bind (header . args) form
(print
(case header
(fp_line (let ((width (assoc 'width args)))
(when width (incf (second width) 3)))
form)
(fp_text (return-from process-form))
(t form)))))
Running the previous loop would then output:
(FP_LINE (START -27.04996 -3.986) (END -27.24996 -3.786) (LAYER F.FAB) (WIDTH 3.1))
(PAD "" NP_THRU_HOLE CIRCLE (AT 35.56 0) (SIZE 3.175 3.175) (DRILL 3.175) (LAYERS *.CU *.MASK) (CLEARANCE 1.5875))
(PAD 96 SMD RECT (AT 1.25 3.08473) (SIZE 0.29972 1.45034) (LAYERS F.CU F.PASTE F.MASK) (CLEARANCE 0.09906))
More safety
From there, you can build more elaborate pipelines, with the help of pattern matching or macros if you want. You have to take into account some safety measures, like binding *read-eval* to nil, using with-standard-io-syntax
and binding *print-circte* to T as suggested by tfb, disallowing fully qualified symbols (by having #\: signal an error), etc. Ultimately, like Shell scripts one-liners, the amount of precautions you add is based on how much you trust your inputs:
;; Load libraries
(ql:quickload '(:alexandria :optima))
;; Import symbols in current package
(use-package :optima)
(use-package :alexandria)
;; Transform source into a stream
(defgeneric ensure-stream (source)
(:method ((source pathname)) (open source))
(:method ((source string)) (make-string-input-stream source))
(:method ((source stream)) source))
;; make reader stop on illegal characters
(defun abort-reader (&rest values)
(error "Aborting reader: ~s" values))
Dedicated package for KiCad symbols (exporting is optional):
(defpackage :kicad
(:use)
(:export #:fp_text
#:fp_line
#:pad
#:size))
Loop over forms:
(defmacro do-forms ((form source &optional result) &body body)
"Loop over forms from source, eventually return result"
(with-gensyms (in form%)
`(with-open-stream (,in (ensure-stream ,source))
(with-standard-io-syntax
(let ((*read-eval* nil)
(*print-circle* t)
(*package* (find-package :kicad))
(*readtable* (copy-readtable)))
(set-macro-character #\: #'abort-reader nil)
(loop
:for ,form% := (read ,in nil ,in)
:until (eq ,form% ,in)
:do (let ((,form ,form%)) ,#body)
:finally (return ,result)))))))
Example:
;; Print lines at which there is a size parameter, and its value
(let ((line 0))
(labels ((size (alist) (second (assoc 'kicad:size alist)))
(emit (size) (when size (print `(:line ,line :size ,size))))
(process (options) (emit (size options))))
(do-forms (form #P"/tmp/ex.cad")
(match form
((list* 'kicad:fp_text _ _ options) (process options))
((list* 'kicad:fp_line options) (process options))
((list* 'kicad:pad _ _ _ options) (process options)))
(incf line))))
Output
(:LINE 2 :SIZE 3.175)
(:LINE 3 :SIZE 0.29972)
Just write a simple Lisp or Scheme script which loops on reading and processes recursively your s-expr as required. On Linux I would recommend using Guile (a good Scheme interpreter) or perhaps Clisp (a simple Common Lisp implementation) or even SBCL (a very powerful Common Lisp).
(You might consider DSSSL, but in your case it is overkill)
Notice that your sample input is not an S-expression, because (layer F.Fab) is not one (since after the dot you should have another s-expression, not an atom like Fab). I guess it is a typo and should be (layer "F.Fab"); or maybe your KiCad software don't process S-expressions, but some other input language (which should be specified, probably in EBNF notation) inspired by S-expressions.
Notice also that KiCad is a free software and has a community with forums and a mailing list. Perhaps you should ask your actual problem there?
PS. We don't know what transformation you have in mind, but Scheme and Common Lisp are really fit for such tasks. In most cases they are extremely simple to code (probably a few lines only).
I am trying to establish a menu so the program can change based on user input. This seems to work but I wanted to see if it was the "RIGHT" way of doing it. Also when the program runs after I input a number I get a (void) displayed. How can I make the (void) go away. Any help would be appreciated....thank you.
(printf "Choose your difficulty\n")
(printf "1. Easy\n")
(printf "2. Medium\n")
(printf "3. Hard\n")
(printf "4. Insane\n")
(define choice (read))
(define (choose c)
(cond [(= c 1)(set! amount 3)]
[(= c 2)(set! amount 7)]
[(= c 3)(set! amount 10)]
[(= c 4)(set! amount 99)]
[else (printf "Invalid choice.\n")]))
(choose choice)
Generally, you should avoid using set!. The functional way to implement this might look like this:
(define (choose c)
(cond [(= c 1) 3]
[(= c 2) 7]
[(= c 3) 10]
[(= c 4) 99]
[else (printf "Invalid choice.\n") (choose (read))]))
(define amount (choose (read)))
Due to the (choose (read)) inside the else clause, the program will ask until it gets a valid input, which is usually what you want. If it isn't, you'll want to figure out a reasonable value for amount to have (e.g. a suitable default).
I know I can read the documentation, but because that requires switching my attention away from my editor and the REPL, I'd like to be able to see a list of functions provided the modules I am using.
Is there something in Racket analogous to Ruby's Foo.methods()?
The function module->exports provides a list of names from a module provide expression.
> (require racket/date)
> (module->exports 'racket/date) ;module name is passed not the module
'()
'((0
(julian/scalinger->string ())
(date->julian/scalinger ())
(find-seconds ())
(date-display-format ())
(date->string ())
(date*->seconds ())
(date->seconds ())
(current-date ())))
reference: racket discussion list
Because module->exports returns two values, define-values is needed to capture the list of functions and the list of macros for use elsewhere:
; my-module.rkt
#lang racket
(provide (all-defined-out))
(define-syntax while
#|
Macros do not allow documentation strings
While macro from StackOverflow.
http://stackoverflow.com/questions/10968212/while-loop-macro-in-drracket
|#
(syntax-rules ()
((_ pred? stmt ...)
(do () ((not pred?))
stmt ...))))
(define my-const 9)
(define (prn a)
"Prints the passed value on a new line"
(printf "\n~a" a))
(define (my-func a)
"Another documentation string"
(prn a))
Referenced in:
;some-other-file.rkt
#lang racket
(require "my-module.rkt")
(define-values (functions-and-constants macros)
(module->exports '"my-module.rkt"))
In REPL:
> functions-and-constants
'((0 (my-const ()) (my-func ()) (prn ())))
> macros
'((0 (while ())))
If you use xrepl, you can use the describe command to get more usefully formatted information:
Welcome to Racket v6.1.0.3.
-> ,describe racket/date
; `racket/date' is a module,
; located at <collects>/racket/date.rkt
; imports: <collects>/racket/base.rkt, <collects>/racket/contract/base.rkt,
; <collects>/racket/promise.rkt.
; direct syntax exports: current-date, date*->seconds,
; date->julian/scalinger, date->seconds, date->string, date-display-format,
; find-seconds, julian/scalinger->string.
So, I have read from
setq and defvar in lisp,
http://www.cs.ucf.edu/courses/cop4020/spr2006/plsetup.html, and
In Lisp, how do I fix "Warning: Assumed Special?"
among other places about the difference between setf and defvar. So I decided to play around with the idea a bit:
CL-USER> (defun foo ()
(setf x 10)
(print x))
; in: DEFUN FOO
; (SETF X 10)
; ==>
; (SETQ X 10)
;
; caught WARNING:
; undefined variable: X
;
; compilation unit finished
; Undefined variable:
; X
; caught 1 WARNING condition
FOO
CL-USER> x
; Evaluation aborted on #<UNBOUND-VARIABLE X {10040F1543}>.
CL-USER> (foo)
10
10
CL-USER> x
10
Okay, I know that setf should be used to change the value of an existing variable, but the undefined variable warning seems to be handled pretty well in SBCL (though I have read that different CL implementations may handle this differently, thus it isn't the best thing to do).
Enter the second test:
CL-USER> (defun bar ()
(defvar y 15)
(print y))
; in: DEFUN BAR
; (PRINT Y)
;
; caught WARNING:
; undefined variable: Y
;
; compilation unit finished
; Undefined variable:
; Y
; caught 1 WARNING condition
BAR
CL-USER> y
; Evaluation aborted on #<UNBOUND-VARIABLE Y {10045033D3}>.
CL-USER> (bar)
15
15
CL-USER> y
15
As per the links, I changed the setf to defvar which I think should create and bind the variable all at once. Now my undefined variable warning gets pushed into the (print y) line ... what is going on here?
As a secondary question, I am expecting the values of any variables assinged within a funciton to be inaccessible outside of the function, as is the case in Python:
>>> def foo():
... x = 10
... print x
...
>>> foo()
10
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
I am guessing this has something to do with the way common lisp deals with scope, ie defvar creates a "global special variabe" ... So I tried one last time with (let ...)
CL-USER> (defun baz ()
(let ((z 10)) (print z))
(incf z 10)
(print z))
; in: DEFUN BAZ
; (INCF Z 10)
; --> LET*
; ==>
; (SETQ Z #:NEW0)
;
; caught WARNING:
; undefined variable: Z
;
; compilation unit finished
; Undefined variable:
; Z
; caught 1 WARNING condition
And after reading What's difference between defvar, defparameter, setf and setq, this one seems to work right:
CL-USER> (defun apple ()
(defparameter x 10)
(print 10))
APPLE
CL-USER> x
; Evaluation aborted on #<UNBOUND-VARIABLE X {1004436993}>.
CL-USER> (apple)
10
10
CL-USER> x
10
Just to reiterate my questions:
1) what is really going on with setf, defvar and let?
2) is there a way to get common lisp to scope the variables inside a function as in the python example?
answering 2) DEFVAR defines a variable. But it has not been executed. So the compiler does not know about the variable in the print form - when compiling the DEFUN form.. It's also inside a DEFUN. Thus it is not on the top-level. As a top-level form the compiler would recognize the DEFVAR and would notice that y is a global special variable.
Just to reiterate my questions: 1) what is really going on with setf, defvar and let?
2) is there a way to get common lisp to scope the variables inside a function as in the python example?
1) SETF sets a variable value, but does not define it. If that variable is undefined, then the Common Lisp standard does not really say what happens. Most Common Lisp implementations will do something useful. Typically it gets executed as if the variable would have been declared special (thus you also get a warning).
DEFVAR is used as a top-level form (usually not inside functions) to define global special variables. Since DEFVAR declares the variable name to be special, it is a very useful convention to write a variable with stars around it: *y* instead of just y.
LET defines a scope for local variables.
2) Common Lisp functions have the parameter list to introduce variables. Other than that they don't define a variable scope. If you want to introduce a local variable inside a function, use LET.
>>> def foo():
... x = 10
... print x
Is
(defun foo ()
(let ((x 10))
(print x)))
Again: a function does not provide a scope for variables, such that assigning a variable inside a function will automagically define it to be function-local. Use LET instead.
Note also that LET is syntactic sugar, mostly: (let ((a 1) (b 2)) (+ a b)) is basically doing the same as ((lambda (a b) (+ a b)) 1 2). It's just a simple function application written differently to improve it for the human reader.
There is also support in Common Lisp for an older syntax:
(defun foo (&aux (x 10))
(print x))
Above defines a local variable X, just like a LET would do.
I'll keep it short and simple:
1) what is really going on with setf, defvar and let?
defvar and defparameter are used to declare and set globally special variables. They only differ when the name is already bound.
setf is used for assignment (to special variables, lexical variables, and other – possibly custom – setfable places.)
let (and let*) creates new variable bindings that are visible inside its body. It may create either lexical or special bindings, depending on (global or local) declarations. If there are no special declarations, lexical bindings will be created.
2) is there a way to get common lisp to scope the variables inside a
function as in the python example?
Put the code inside let's body, where the binding is visible:
CL-USER> (defun baz ()
(let ((z 10))
(print z)
(incf z 10) ; i.e. (setf z (+ z 10))
(print z)))
BAZ
CL-USER> (baz)
10
20
20
CL-USER> z
; Evaluation aborted on #<UNBOUND-VARIABLE #x186C611E>.