Racket equivalent of /dev/null? - racket

If I have a function that prints to (current-output-port), is there an easy way to run the function without it printing to the output port?
Previously, I've used /dev/null as an output target:
(with-output-to-file "/dev/null" #:exists 'append
(lambda () (displayln "hello world")))
This is easy, but platform dependent. Also I'll sometimes forget the #:exists flag.

Yes! Use open-output-nowhere from racket/port.
(parameterize ([current-output-port (open-output-nowhere)])
(displayln "hello world"))
If you want to hide error output, override current-error-port instead / also.

Related

How do I make my Racket-designed language run scripts from external files?

I've got a custom language I'm designing in Racket, let's call it waffle.
Let's say I have
(define (printstr . input)
(if (string? (car input))
(write (string-join input ""))
(write input)))
; ... a whole bunch of other definitions
(command-line
#:multi
[("-v" "--verbose") "more verbose" (set! loglevel (add1 loglevel))]
[("-q" "--quiet") "be quiet" (set! loglevel 0)]
#:once-any
[("-i" "--in-place") "edit in-place" (set! mode 'in-place)]
[("-c" "--create-new") "create a new file" (set! mode 'new)]
[("-n" "--dry-run") "do nothing" (set! mode #f)]
#:once-each
[("-d" "--directory") dir "work in a given directory" (set! root dir)]
#:help-labels "operations to perform:"
#:multi
[("+l" "++line") "add a line" (set! ops `(,#ops "add"))]
[("-l" "--line") "delete a line" (set! ops `(,#ops "delete"))]
[("-e" "--edit") "edit a line" (set! ops `(,#ops "edit"))]
#:args (file)
(define in (open-input-file file))
; This is probably where I'm going wrong with how my language REPL evaluates files passed to it.
(eval (file->list file) ns))
Then I create an executable from DrRacket using 'Racket [menu] -> Create Executable ... -> [Type] Launcher'. Name is e.g. waffle-test.
I've got a file written in my waffle language, hello.waffle:
(printstr "Hello!")
I expect this to print 'Hello!' on the command line and then exit without errors. But I get a strange error I don't understand, and I get my prompt back without a newline.
$ ./waffle-test hello.waffle
application: not a procedure;
expected a procedure that can be applied to arguments
given: #<void>
arguments...: [none]
context...:
eval-one-top12
"/home/connie/Desktop/racket-ffgardfghf/waffle": [running body]
temp37_0
for-loop
run-module-instance!125
perform-require!78
"Hello!" $
I know you're not supposed to use eval but I can't find out how to make my language executable read and run files I pass to it. What is the best approach to doing this?
Just with this simple test I figured out a couple of things:
#!racket
(file->list "test.waffle")
With test.waffle as:
(waffle me)
(waffle it)
The repl printed:
((waffle me)
(waffle it))
However that is not valid code, even if waffle is a valid procedure. You need it to look like this:
(begin
(waffle me)
(waffle it))
Now you can do this by require your language to have it, but you can also just cons a begin to the resulting structure and eval will evaluate each top level form one by one in order.
You will run into problems with using eval. You'll know that soon enough. The correct way to make an interpreter is by creating your own eval that implements your languages syntax and takes en environment with primitives. It has an interface to use the host, but not regardless. With eval waffle programs has access to all internals and you're not really creating an interpreter since you just expose Racket.
I remember someone did the same with Ruby and had a web page and someone just tried to type in a command that deleted all the files on the system and the web service went away.
By fixing a few bugs in my code I managed to solve my problem!
I changed
(eval (file->list file) ns))
to
(define program (cons 'begin (file->list file)))
(eval program ns))
I also changed the 'printstr' function from
(define (printstr . input)
(if (string? (car input))
(write (string-join input ""))
(write input)))
to
(define (printstr input)
(displayln input))

How to call a racket procedure from terminal by giving command line argumands

I have a racket file called foo.rkt Inside that file I have a procedure called textify and it takes 2 parameters. Now how can I call this procedure from terminal ? What I want to do is simply:
> racket foo.rkt myfirstarg mysecondarg
and then I want this call to activate (textify myfirstarg mysecondarg) procedure. Is this possible ?
Here is the content of foo.rkt:
#lang racket
(require wxme)
(provide
(contract-out
[textify (-> path-string? path-string? void?)]))
(define (textify in out)
(call-with-input-file in
(λ (in-port)
(call-with-output-file out
(λ (out-port)
(copy-port (wxme-port->text-port in-port) out-port))
#:exists 'truncate))))
You can simply do this as the last expression in your file:
(apply textify (vector->list (current-command-line-arguments)))
If you are making a more advanced program that has switches you can use command-line that does this for you.

Suppress output from print function in Lisp

I'm fairly new to Lisp, and I've run into a printing issue. I have one function which does printing to the standard output (among other things). I want to then run this function through another function where it still runs the same but instead nothing gets printed to the standard output.
Here is a simple example of what I mean. I have the following two functions described:
(defun does-printing()
(print "This goes to standard output."))
(defun run-other-function (function)
(funcall function)
(values))
Here's a dribble of what happens when I run this,
;; Dribble of #<IO TERMINAL-STREAM> started on 2014-10-05 21:49:49.
#<OUTPUT BUFFERED FILE-STREAM CHARACTER #P"example.out">
[7]> (run-other-function #'does-printing)
"This goes to standard output."
[8]> (dribble)
;; Dribble of #<IO TERMINAL-STREAM> finished on 2014-10-05 21:50:09.
Note that the printing function still prints to the standard output. It'd like to be able to suppress this printing somehow when running does-printing through run-other-function. I have tried many different variations of phrasing of my problem when searching for solutions, but nothing is getting at what I would like to do.
The simplest solution is to create an empty broadcast stream.
(with-open-stream (*standard-output* (make-broadcast-stream))
(call-some-function-1)
...
(call-some-function-n))
If a broadcast stream has no component stream all output will be discarded. Above binds the *standard-output* to such a stream. This does not cons up any data and it is portable.
You can just redirect your standard-output to some place. For example into /dev/null if you have one in your operating system. It looks like very idiomatic UNIX-way output suppressing.
Note, that you shouldn't set it to NIL, because print will signal type error in this case.
(defun does-printing()
(print "This goes to standard output."))
(defun run-other-function (function)
(with-open-file (*standard-output*
"/dev/null"
:direction :output
:if-exists :supersede)
(funcall function)
(values)))
CL-USER> (run-other-function #'does-printing)
; No value
Other option (and it may be better) is to use with-output-to-string, so you can capture this output value or just ignore it. Is think it's better, because why to do IO if we don't need it, and also it must work on any OS.
(defun run-other-function (function)
(with-output-to-string (*standard-output*
(make-array '(0)
:element-type 'base-char
:fill-pointer 0 :adjustable t))
(funcall function)
(values)))
If you doing it a lot, you can wrap it into macro or even function, to use in place of funcall.
(defun does-printing()
(print "This goes to standard output.")
"My result")
(defun funcall-with-no-output (fn)
(with-output-to-string (*standard-output*
(make-array '(0)
:element-type 'base-char
:fill-pointer 0 :adjustable t))
(funcall fn)))
CL-USER> (funcall-with-no-output #'does-printing)
"My result"
But i think macro will be more general and idiomatic for this case (may be I'm wrong).
(defmacro with-suppressed-output (&body body)
`(with-output-to-string (*standard-output*
(make-array '(0)
:element-type 'base-char
:fill-pointer 0 :adjustable t))
,#body))
So you can call many forms in with-suppressed-output.

Silently call defun from emacsclient

During the compilation of sources, I would like GNU Make to call an emacs defun.
For this I have 2 options:
Start a new emacs instance, and load the desired function and call it.
Call the defun from the emacsclient like:
emacsclient --eval "(my-emacs-defun)"
The latter has the advantage, it is faster, because the emacs server is already running and has the desired defun loaded.
But this also has a disadvantage, if (message ...) is called from (my-emacs-defun), it interrupts my active emacs session.
I could try to modify (my-emacs-defun) so (message ...) isn't called, but is really hard when using emacs built-in functions.
Therefore I would like to know how to suppress the (message ...) from (my-emacs-defun).
Is it possible to alter the (message ...) behavior when being called (my-emacs-defun)? Can I use(defadvice)` for this?
EDIT
The real problem is, the message is displayed the minibuffer. It is irritating when using the minibuffer at that time (e.g. during (find-file)).
Just redefine the message function for your call (temporarily):
(flet ((message (msg) ))
(my-emacs-defun)))
Because of dynamic scoping for global functions, the name message will be redefined while the execution is inside the flet-expression, and it will return it's original sense after it exits the flet.
Example:
(defun verbose ()
(message "hi"))
(let ()
(message "one")
(flet ((message (msg) ))
(verbose))
(message "two"))
; ->
; one
; two
You could've also temporarily rebind s Messages buffer, but I don't know where is it stored.
You can restore the message displayed in the echo area before the function call like this:
(let ((msg (current-message)))
(do-something-that-calls-message)
(message "%s" (or msg "")))
(with-temp-message "" (my-emacs-func))
I've looked in the emacs source code and I found this hack:
(let ((message-log-max nil)
(executing-kbd-macro t))
(my-emacs-defun))
This does suppress all message, but still while (find-file) the focus of the minibuffer is lost.
I decided to go for the first option: without emacsclient.
To be more precise I now use:
emacs --batch --eval "(my-emacs-defun)"
In my Makefile it looks like this:
sometarget:
#emacs --batch --eval "$${elisp_code}"
define elisp_code
(require 'something)
(my-emacs-defun)
endif
This also seems to be fast.
Even better:
define emacs_script_content=
(require 'something)
(my-emacs-defun)
endef
export emacs_script_content
emacs-script:
#echo $${emacs_script_content} > $#
.INTERMEDIATE: emacs-script
some-target: emacs-script
#emacs --script $<
This way you won't get errors when calling make functions or when having quoted "text" in the script.

Print output into a file or not print output?

I'd like to save or ignore outputs when I execute a specific function in lisp. I use Emacs and CCL. For example,
(defun foo (x) (format t "x = ~s~%" x))
and if I execute the function, it prints out "x = 5". But I don't want to printout in a buffer, because if I have a large amount of iteration, the speed of simulation will be decreased.
Any idea?
You can temporarily redirect standard output by binding *standard-output* to a stream. For example, a broadcast stream with no output streams will serve as a black hole for output:
(let ((*standard-output* (make-broadcast-stream)))
(foo 10)
(foo 20))
;; Does not output anything.
You can also do this with other binding constructs, such as with-output-to-string or with-open-file:
(with-output-to-string (*standard-output*)
(foo 10)
(foo 20))
;; Does not print anything;
;; returns the output as a string instead.
(with-open-file (*standard-output* "/tmp/foo.txt" :direction :output)
(foo 10)
(foo 20))
;; Does not print anything;
;; writes the output to /tmp/foo.txt instead.
Instead of t as the first argument to format, you can give it an output file stream and your output for that statement will be sent to that file stream.
However having excessive disk I/O will also will increase your running time, hence you can consider having two modes like a debug and a release mode for your program where the debug mode prints all the diagnostic messages and the release mode does not print anything at all.
I'm not sure I understand your question, but the second argument to format is a stream. If you set it to t it prints to standard output, but you can also set it to an open file.
So something like this would allow you to select where the output goes:
;;output to file:
(setf *stream* (open "myfile" :direction :output
:if-exists :supersede)
;;alternative to output to standard output:
;;(setf *stream* t)
(defun foo (x) (format *stream* "x = ~s~%" x))
(foo 10)
(close *stream*) ;; only if output sent to a file