What's the best way to read input from stdin in racket?
In particular I'd like something like cin from c++ or scanf from c where I specify the types of things I want read and they are returned.
read-line is easy. To be portable across Unix and Windows, additional option is required.
(read-line (current-input-port) 'any)
Return and linefeed characters are detected after the conversions that
are automatically performed when reading a file in text mode. For
example, reading a file in text mode on Windows automatically changes
return-linefeed combinations to a linefeed. Thus, when a file is
opened in text mode, 'linefeed is usually the appropriate read-line
mode.
So, 'any is required to be portable when the input port is not a file (standard input).
Test program:
#lang racket
(let loop ()
(display "Input: ")
(define a (read-line (current-input-port) 'any))
(printf "input: ~a, length: ~a, last character: ~a\n"
a
(string-length a)
(char->integer (string-ref a (- (string-length a) 1))))
(loop))
In Windows, replace (read-line (current-input-port) 'any) with (read-line) and see what happens.
You can do pretty much everything you want to... at the low level, I would suggest (read-line) and (read-bytes). For higher-level processing (as e.g. scanf does), I would suggest a regexp-match on the input. For instance
(regexp-match #px" *([0-9]+)" (current-input-port))
I'd use the read procedure for the general case. If the data type to be read is known beforehand, use read-char, read-string, read-bytes.
Also, take a look at this implemenation for reading formatted input - a scanf in Scheme.
Here's a basis for line-by-line processing in Racket Scheme. It doesn't split an input line into multiple words, or do typed input, but this seems like a good place to put it.
(define (get)
(read-line (current-input-port)))
(define (put . vs)
(for-each display vs)
(displayln ""))
(define (sed fn)
(let ((line (get)))
(if (not (eof-object? line))
(begin
(fn line)
(sed fn))
'true)))
(sed (lambda (line)
(put "Hello, " line)))
Here's one that does split input, also encodes CSV for good measure.
(define (get)
(read-line (current-input-port)))
(define split string-split)
(define sep ",")
(define enc identity)
(define (enc-csv s)
(string-append "\"" (string-replace s "\"" "\"\"") "\""))
(define enc enc-csv)
(define (put . vs)
(displayln (string-join (map enc vs) sep)))
(define (sed fn)
(let ((line (get)))
(if (not (eof-object? line))
(begin
(fn line)
(sed fn))
'true)))
(sed (lambda (line)
(apply put (split line))))
This works in Racket. I'm not sure how much of it is specific to Racket. It doesn't seem to work in Chicken or Guile.
Related
If Guile is not the best Scheme for this usage, then which one should I be looking at? I'm basically looking for a Guile equivalent of awk '{print $N}'. If Scheme can't do this, then I'd like to know why not.
Guile changed its I/O a bit between 2.0 and 2.2, so this uses r6rs I/O which (hopefully) works the same in both, but I haven't tested with 2.2.
This can be optimized further.
#!/usr/bin/guile \
-e start -s
!#
(use-modules (rnrs io ports))
;;; Reads one line from current-input-port and prints the field indicated by
;;; field-num. If the line does not have enough fields, it prints a newline.
;;; Returns the field, an empty string, or #f if end of file is reached.
(define (get-field field-num)
(let ((line (get-line (current-input-port))))
(if (eof-object? line)
#f
(let ((fields (string-tokenize line)))
(if (< field-num (length fields))
(let ((field (list-ref fields field-num)))
(put-string (current-output-port)
(string-append field "\n"))
field)
(and (put-string (current-output-port) "\n")
""))))))
;;; Repeat get-field until until end of file is reached
(define (get-all-fields field-num)
(if (get-field field-num)
(get-all-fields field-num)
#f))
(define (start args)
(if (and (> (length args) 1)
(integer? (string->number (list-ref args 1))))
(get-all-fields (1- (string->number (list-ref args 1))))
(display (string-join
`("Usage:" ,(list-ref args 0) "<field-number>\n")
" "))))
At my blog I have an essay giving a set of functions that make it easy to handle delimited text files.
I am trying to implement a stream->file function that takes a stream of characters and prints it to a file. I feel I am close to a solution, but cannot figure out how to complete this.
(define stream->file
(lambda (filename str)
(let ((output (open-output-file filename)))
(letrec
((build-output-stream
(lambda (str)
(let ((char (write-char (stream-first str) output)))
(if (eof-object? char)
(begin
(close-output-port output)
empty-stream)
(stream-cons char (build-output-stream (stream-rest str))))))))
(build-output-stream str)))))
This doesn't do anything other than say #<stream> in the output. It creates a file, but does not write to it. What am I missing?
I find your code overly complicated. You need to write each element in the stream and since this is pure side effect you might as well use stream-for-each. Instead of doing the file port handling it's easier to use with-output-to-file since it will close the port when the thunk is done. This is the result:
(define (stream->file file-path stream)
(with-output-to-file file-path
(thunk (stream-for-each display stream))))
(stream->file "test-stream.txt" (stream #\t #\e #\s #\t #\newline))
; undefined, makes a file named "test-stream.txt" with the content "test\n"
I've got
(define (compiler exp)
(define (printer line) (display line) (newline))
(init-generators)
(let ((res (compile (append bootstrap (list exp)) function-res '())))
(map printer c-string-list)
(display bootstrap-c-code)
(add-c-function 'startup '(env) res)
(map (lambda (function) (map printer function) (newline)) c-function-list)
'ok))
and I need
(define (compile file-name)
(compiler (load file-name)))
But it doesn't work this way. It's executing directly. How can I load it as expression? (exp)
Are you looking for the read function, as opposed to load? Without knowing more about the implementation you're using, I can only point to the read documentation from r5rs. Use open-input-file to get a port from the filename, and then read from that port.
What's the content of the file file-name? If it's an expression, load will execute it, for instance if file-name contains (+ 1 1), (load filename) will return 2.
On the other hand, if file-name contains a list of symbols, they will be read as they are, for example if file-name contains '(+ 1 1) (notice the quote at the beginning), then (load filename) will return (+ 1 1), which I'm guessing is what you mean by saying that you need to load it as an expression.
If you need to load several expressions inside the file, surround them with a quote and a begin in the file:
'(begin
<your code here>
)
I often find myself converting code like this:
before do
:something
end
to
before { :something }
Is there a way to automate this task in emacs? I use ruby-mode and rinary, but they're not too helpful here.
ruby-mode in Emacs 24.3 and newer has the command ruby-toggle-block.
The default binding is C-c {.
I am sure it can be made shorter and better, but for now I've got the following:
(defun ruby-get-containing-block ()
(let ((pos (point))
(block nil))
(save-match-data
(save-excursion
(catch 'break
;; If in the middle of or at end of do, go back until at start
(while (and (not (looking-at "do"))
(string-equal (word-at-point) "do"))
(backward-char 1))
;; Keep searching for the containing block (i.e. the block that begins
;; before our point, and ends after it)
(while (not block)
(if (looking-at "do\\|{")
(let ((start (point)))
(ruby-forward-sexp)
(if (> (point) pos)
(setq block (cons start (point)))
(goto-char start))))
(if (not (search-backward-regexp "do\\|{" (point-min) t))
(throw 'break nil))))))
block))
(defun ruby-goto-containing-block-start ()
(interactive)
(let ((block (ruby-get-containing-block)))
(if block
(goto-char (car block)))))
(defun ruby-flip-containing-block-type ()
(interactive)
(save-excursion
(let ((block (ruby-get-containing-block)))
(goto-char (car block))
(save-match-data
(let ((strings (if (looking-at "do")
(cons
(if (= 3 (count-lines (car block) (cdr block)))
"do\\( *|[^|]+|\\)? *\n *\\(.*?\\) *\n *end"
"do\\( *|[^|]+|\\)? *\\(\\(.*\n?\\)+\\) *end")
"{\\1 \\2 }")
(cons
"{\\( *|[^|]+|\\)? *\\(\\(.*\n?\\)+\\) *}"
(if (= 1 (count-lines (car block) (cdr block)))
"do\\1\n\\2\nend"
"do\\1\\2end")))))
(when (re-search-forward (car strings) (cdr block) t)
(replace-match (cdr strings) t)
(delete-trailing-whitespace (match-beginning 0) (match-end 0))
(indent-region (match-beginning 0) (match-end 0))))))))
There are two functions to be bound to keys: ruby-goto-containing-block-start and ruby-flip-containing-block-type.
Either command works anywhere inside a block, and hopefully they can skip blocks that should be skipped - although that shouldn't be an issue if you are converting to a short block format.
The ruby-flip-containing-block-type collapses three line do .. end blocks to single line {} and vice versa. If the blocks are not exactly 3 lines and 1 line long, it should leave them alone.
I am using this on my ruby setup now, so I would appreciate improvements.
You could use a regular expression that crosses newlines.
/do(C-q C-j\?)*(.*)(C-q C-j\?)*end/
and replace with
{\2 }
Something like that could work. You could then customize it until it does exactly what you need and bind it to a macro so that you can whip it out and impress your friends anytime!
I tested the above regexes in vi (my editor of choice) and they worked. So something similar should work for you.
For more information, make sure to checkout the emacs wiki!
Here is a function. I am an elisp beginner. It only goes one way; from do to {. let me know if it works for you.
I'm working my way through SICP, using both the Ableson/Sussman
lectures and the Berkeley 61A lectures, which are far more my
speed. I'd like to do some of the Berkeley homework, but need the
definitions for sentence, butfirst, butlast and so forth. It looks like at one time there was a simply scheme language built in to Dr. Scheme, but version 4.1.5, the most recent, doesn't have it. From Planet PLT
I thought I could simply add (require (planet "simply-scheme.ss" ("dyoo"
"simply-scheme" 1 0))) in my definitions window. I get
require: PLaneT
could not find the requested package: Server had no matching package:
No package matched the specified criteria
I tried grabbing the simply.scm file from here
and pasted it into my Dr Scheme definitions window, but it doesn't work:
In Advanced Student mode, I get
read: illegal use of "."
For the line (lambda (string . args) in the following code.
(define whoops
(let ((string? string?)
(string-append string-append)
(error error)
(cons cons)
(map map)
(apply apply))
(define (error-printform x)
(if (string? x)
(string-append "\"" x "\"")
x))
(lambda (string . args)
(apply error (cons string (map error-printform args))))))
In R5RS I get
set!: cannot mutate module-required identifier in: number->string
(line 7 of the following code)
(if (char=? #\+ (string-ref (number->string 1.0) 0))
(let ((old-ns number->string)
(char=? char=?)
(string-ref string-ref)
(substring substring)
(string-length string-length))
(set! number->string
(lambda args
(let ((result (apply old-ns args)))
(if (char=? #\+ (string-ref result 0))
(substring result 1 (string-length result))
result)))))
'no-problem)
Advanced Student will never really work for you unless you're following examples that were designed for it. Most books and examples will assume R5RS or something like it. I would recommend using the Pretty Big language, as that includes both R5RS, as well as the PLT require syntax, and a few other things.
In order to use the Simply Scheme package from PLaneT, you will need to use the new require syntax (you can find this on the package listing page; it looks like the docs for the package haven't been updated):
(require (planet dyoo/simply-scheme:1:2/simply-scheme))
Following up; the Simply Scheme support library for Racket can be found at:
http://planet.plt-scheme.org/display.ss?package=simply-scheme.plt&owner=dyoo
I did some light documentation updates in http://planet.plt-scheme.org/package-source/dyoo/simply-scheme.plt/2/1/planet-docs/manual/index.html.