Idiomatic way to write Clojure code for repeatedly reading lines from the console? - command-line

Recently I was writing a little CLI script which needed to repeatedly read dates from the console (the number of dates to read was calculated and could be different each time). Sample Ruby code to give you the idea:
dates = x.times.collect { print "Enter date: "; Date.parse(gets.chomp) }
Just for the heck of it, I wrote the script in Clojure, and wound up using some rather ugly code with swap! and loop...recur. I'm wondering what the cleanest way to achieve the desired effect in Clojure would be. (Clojure does have dotimes, but it doesn't retain the values returned from evaluating the body... as might be expected from a language which emphasizes pure functional programming.)

read-line returns nil when the end of file is reached. On the console that is when you press CTRL-d (CTRL-z on Windows).
You could use this code to take advantage of this:
(doseq [line (repeatedly read-line) :while line]
(do-something-with line))
If you must read a fixed number of lines you can use:
(repeatedly n read-line)

If your goal is to end up with a sequence of exactly x dates entered by user then:
(for [line (repeatedly x read-line)] (DateFormat/parse line))
or using map:
(map DateFormat/parse (repeatedly x read-line))
Beware of lazy sequences in Clojure: user will be asked to enter more dates as they are needed. If your goal is for user to enter all dates at once (say at startup) then use doall:
(map DateFormat/parse (doall (repeatedly x read-line)))
This will read all dates at once, but will parse them lazily still, so date format validation could fail much later in your program. You can move doall one level up to parse promptly as well:
(doall (map DateFormat/parse (repeatedly x read-line)))
And you can use a helper function to read line with prompt:
(defn read-line-with-prompt [prompt]
(print prompt)
(read-line))
Then replace read-line with either:
#(read-line-with-prompt "Enter date: ")
or
(partial read-line-with-prompt "Enter date: ")

You can do something like this:
(defn read-dates [n]
(doall (for [_ (range n)] (java.util.Date/parse (read-line)))))
(def my-dates (read-dates 5)) ;Read 5 dates from console

Related

Does TASM allow a macro to be used as an operand?

I am attempting to port a macro from MASM6 to TASM5 (in IDEAL mode) and I am encountering errors. The macro itself assembles fine, but when I attempt to call it, I receive the following error during assembly:
Error xxx.asm(##) Can't use macro name in expression: M_SWAP16
The macro takes the numeric value from a text macro and performs a byte swap. The macro is generally called with ops that take immediate values or during variable initialization.
MACRO M_swap16 operand
LOCAL result
result = (((operand and 0FFh) shl 8) or ((operand and 0FF00h) shr 8))
exitm %result
ENDM
IPPROTO_TCP EQU 6
.
.
.
mov [protocol], M_swap16(IPPROTO_TCP) ; fails
.
.
.
protocol DW ?
protocol_default DW M_swap16(IPPROTO_TCP) ; fails
It works fine in MASM 6.11. Switching TASM from IDEAL to MASM mode doesn't help. Neither does moving the macro into the EQU statement. Ideas?
Unfortunately TASM5 doesn't appear to support macros returning results to expressions at least according to the last official docs. This is also what the error you are seeing is saying. More specifically, the EXITM directive doesn't take an argument like MASM can regardless of the mode you are in. However TASM's macros can still emit a line of code, so if you aren't worried about passing the expression in to the macro, I propose the following workaround (IDEAL mode):
MACRO M_swap16_EXPRESSION expr,operand
LOCAL result
result = (((operand and 0FFh) shl 8) or ((operand and 0FF00h) shr 8))
expr result
ENDM
The macro above takes an additional argument "expr" as the 1st argument which is the assembly expression you were trying to plug the original expression in. It will perform the assembly-time arithmetic on the operand and emit the final assembly line. It can be used like this:
M_swap16_EXPRESSION <mov [protocol],>,IPPROTO_TCP
...
M_swap16_EXPRESSION <protocol_default DW>,IPPROTO_TCP
I admit its ugly, but it might be the next best thing if you must use TASM.

LISP: formatting the output of read-line while reading a game board from a file

I am trying to read the board from a text file, but while printing it is also printing the newline and inverted commas as:
(with-open-file (stream "brd1.txt")
(do ((line (read-line stream nil)
(read-line stream nil)))
((null line))
(print line)))
"+ + +^M"
" 3 3 ^M"
"+ + +^M"
" ^M"
"+ + +"
NIL
I am new to LISP. Could somebody help me to format these lines to print the exact board as:
+ + +
3 3
+ + +
+ + +
Input
Apparently you're trying to feed a DOS text file with CRLF-delimited lines to a Lisp implementation that assumes the lines to be LF-delimited in the Unix fashion. Note that read-line strips the newlines, so in our case LF's are stripped, but CR's are treated as ordinary characters and thus remain in the string.
Newlines are platform specific and hence implementation dependent in Lisp. What's more, it seems that neither asdf nor asdf-encodings address this issue. The way I see it you have the following options:
trim the CR's manually e. g. like this:
(string-right-trim '(\#Return) line)
use one of asdf's functions slurp-stream-string and slurp-stream-lines;
use some implementation specific mechanism to specify the encoding;
convert your text file to the Unix format.
Output
As already noted, PRINT is actually a human-readable serialisation. There is a bunch of printing functions on CLHS's page for WRITE and, of course, FORMAT. In order to output a string you can also use WRITE-STRING (without appending a newline) or WRITE-LINE (with a newline).
UPD
Actually UIOP (not ASDF!) exports the utility function UIOP:STRIPLN, which does the following, according to its docstring:
"Strip a string X from any ending CR, LF or CRLF.
Return two values, the stripped string and the ending that was stripped,
or the original value and NIL if no stripping took place.
Since our STRCAT accepts NIL as empty string designator,
the two results passed to STRCAT always reconstitute the original string"
As you can see from the documentation, print "produces output suitable for input to read". Use format instead:
(format t "~a" line)

In newLISP, quote is different from '?

I begin to learn newlisp, but the quote and ' puzzle me.
> (= '(quote 1) ''1)
nil
or
> (first (quote (quote 1)))
quote
> (first ''1)
ERR: array, list or string expected in function first : ''1
in newlisp, quote is different from ' ?
or, this is a bug?
There is a subtle difference between the two. The single quote is resolved during source code translation, when the quoted cell is wrapped into a protecting envelope. The function quote does the same but during evaluation. For most purposes they behave in the same way.
So the function quote is more like the original Lisp quote. The ' is an optimization performed during code translation. If you want to know more about code translation and evaluation, compare the functions read-expr and eval-string.

Command line processing in Racket contains embedded void

What about command-line processing in racket do I not understand?
For example, I just want to process the first argument as foo.html.
From the command-line I run it as:
racket cmd.rkt foo.html
Unfortunately that just returns:
foo.html'#(#<void>)
Here's the code for cmd.rkt:
(for/vector ([i (current-command-line-arguments)])
(display i))
for/vector isn't called that because it iterates over vectors, it's called that because it accumulates the results of its body expression into a vector. So for each commandline argument it evaluates the display call, which prints the argument and returns #<void>, and accumulates the result into a vector of void values.
Use for instead and the problem will go away.
Let's see what the code is doing. With this command...
racket cmd.rkt foo.html
... You're telling the interpreter: run cmd.rkt and pass a single parameter, the string "foo.html".
In the script, this code...
(for/vector ([i (current-command-line-arguments)])
(display i))
...Is iterating over the command line arguments (a single one in the example), displaying each one in turn. Do notice that display returns #<void> as its value, and for/vector creates a vector with all the returned values in the iteration, so naturally this is the output:
foo.html'#(#<void>)
The first part, foo.html is the result of displaying the single command line argument that was passed. The second part, '#(#<void>) is a vector with a single element, #<void>, which as mentioned before, is the result of calling display.
Finally, as has been mentioned in the other answers: if you only intended to print all of the received command line arguments, then avoid using for/vector - you don't want to create a new vector, only traverse and print the arguments and a simple for will suffice. This should work, and includes #GregHendershott's recommended optimization regarding the use of in-vector:
(for ([i (in-vector (current-command-line-arguments))])
(display i))

How can I get a substring of a string in Emacs Lisp?

When I have a string like "Test.m", how can I get just the substring "Test" from that via elisp? I'm trying to use this in my .emacs file.
One way is to use substring (or substring-no-properties):
(substring "Test.m" 0 -2) => "Test"
(substring STRING FROM &optional TO )
Return a new string whose contents are a substring of STRING. The
returned string consists of the characters between index FROM
(inclusive) and index TO (exclusive) of STRING. FROM and TO are
zero-indexed: 0 means the first character of STRING. Negative values
are counted from the end of STRING. If TO is nil, the substring runs
to the end of STRING.
Stefan's answer is idiomatic, when you just need a filename without extension. However, if you manipulate files and filepaths heavily in your code, i recommend installing Johan Andersson's f.el file and directory API, because it provides many functions absent in Emacs with a consistent API. Check out functions f-base and f-no-ext:
(f-base "~/doc/index.org") ; => "index"
(f-no-ext "~/doc/index.org") ; => "~/doc/index"
If, instead, you work with strings often, install Magnar Sveen's s.el for the same reasons. You might be interested in s-chop-suffix:
(s-chop-suffix ".org" "~/doc/index.org") ; => "~/doc/index"
For generic substring retrieval use dkim's answer.
In your particular case, you might like to use file-name-sans-extension.
Probably the most flexible option (although it's not clear if you need flexibility) would be to use replace-regexp-in-string:
See C-hf replace-regexp-in-string RET
e.g.:
(replace-regexp-in-string "\\..*" "" "Test.m")