Writing a lazy, functional, interactive command line application in Clojure - command-line

I'm wondering: what is the best way to write a Clojure program that interacts with a user or another program thorough stdin and stdout?
Clearly it would be possible to write some kind of imperative loop, but I'm hoping to find something more lazy / functional, a bit inspired by Haskell's "interact" function.

This was the best I could come up with:
(defn interact [f]
(lazy-seq
(cons (do (let [input (read-line)
result (f input)]
(println result)
{:input input :result result}))
(interact f))))
You could use it like this:
(def session
(take-while #(not= (:result %) 0)
(interact count)))
REPL:
user=> (str "Total Length: " (reduce #(+ %1 (:result %2)) 0 session))
foobar
6
stackoverflow
13
0
"Total Length: 19"
user=> session
({:input "foobar", :result 6} {:input "stackoverflow", :result 13})

Related

Is it possible to turn off qualification of symbols when using clojure syntax quote in a macro?

I am generating emacs elisp code from a clojure function. I originally started off using a defmacro, but I realized since I'm going cross-platform and have to manually eval the code into the elisp environment anyway, I can just as easily use a standard clojure function. But basically what I'm doing is very macro-ish.
I am doing this because my goal is to create a DSL from which I will generate code in elisp, clojure/java, clojurescript/javascript, and maybe even haskell.
My "macro" looks like the following:
(defn vt-fun-3 []
(let [hlq "vt"]
(let [
f0 'list
f1 '(quote (defun vt-inc (n) (+ n 1)))
f2 '(quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8))))]
`(~f0 ~f1 ~f2)
)))
This generates a list of two function definitions -- the generated elisp defun and a unit test:
(list (quote (defun vt-inc (n) (+ n 1))) (quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8)))))
Then from an emacs scratch buffer, I utilize clomacs https://github.com/clojure-emacs/clomacs to import into the elisp environment:
(clomacs-defun vt-fun-3 casc-gen.core/vt-fun-3)
(progn
(eval (nth 0 (eval (read (vt-fun-3)))))
(eval (nth 1 (eval (read (vt-fun-3))))))
From here I can then run the function and the unit test:
(vt-inc 4)
--> 5
(ert "vt-inc-test")
--> t
Note: like all macros, the syntax quoting and escaping is very fragile. It took me a while to figure out the proper way to get it eval properly in elisp (the whole "(quote (list..)" prefix thing).
Anyway, as suggested by the presences of the "hlq" (high-level-qualifier) on the first "let", I want to prefix any generated symbols with this hlq instead of hard-coding it.
Unfortunately, when I use standard quotes and escapes on the "f1" for instance:
f1 '(quote (defun ~hlq -inc (n) (+ n 1)))
This generates:
(list (quote (defun (clojure.core/unquote hlq) -inc (n) (+ n 1)))
(quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8)))))
In other words it substitutes 'clojure.core/unquote' for "~" which is not what I want.
The clojure syntax back-quote:
f1 `(quote (defun ~hlq -inc (n) (+ n 1)))
doesn't have this problem:
(list (quote (casc-gen.core/defun vt casc-gen.core/-inc (casc-gen.core/n) (clojure.core/+ casc-gen.core/n 1))) (quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8)))))
It properly escapes and inserts "vt" as I want (I still have to work out to concat to the stem of the name, but I'm not worried about that).
Problem solved, right? Unfortunately syntax quote fully qualifies all the symbols, which I don't want since the code will be running under elisp.
Is there a way to turn off the qualifying of symbols when using the syntax quote (back tick)?
It also seems to me that the syntax quote is more "capable" than the standard quote. Is this true? Or can you, by trickery, always make the standard quote behave the same as the syntax quote? If you cannot turn off qualification with syntax quote, how could I get this working with the standard quote? Would I gain anything by trying to do this as a defmacro instead?
The worst case scenario is I have to run a regex on the generated elisp and manually remove any qualifications.
There is no way to "turn off" the qualifying of symbols when using syntax quote. You can do this however:
(let [hlq 'vt] `(~'quote (~'defun ~hlq ~'-inc (~'n) (~'+ ~'n 1))))
Which is admittedly pretty tedious. The equivalent without syntax quote is:
(let [hlq 'vt] (list 'quote (list 'defun hlq '-inc '(n) '(+ n 1))))
There is no way to get your desired output when using standard quote prefixing the entire form however.
As to the issue of using defmacro instead, as far as I understand your intentions, I don't think you would gain anything by using a macro.
Based on the input from justncon, here is my final solution. I had to do a little extra formatting to get the string concat on the function name right, but everything was pretty much like he recommended:
(defn vt-gen-4 []
(let [hlq 'vt]
(let [
f1 `(~'quote (~'defun ~(symbol (str hlq "-inc")) (~'n) (~'+ ~'n 1)))
f2 `(~'quote (~'defun ~(symbol (str hlq "-inc-test")) () (~'should (~'= (~(symbol (str hlq "-inc")) 7) 8))))
]
`(~'list ~f1 ~f2))))
What I learned:
syntax quote is the way to go, you just have to know how to control unquoting at the elemental level.
~' (tilde quote) is my friend here. Within a syntax quote expression, if you specify ~' before either a function or var it will be passed through to the caller as specified.
Take the expression (+ 1 1)
Here is a synopsis of how this expression will expand within a syntax quote expression based on various levels of escaping:
(defn vt-foo []
(println "(+ 1 1) -> " `(+ 1 1)) --> (clojure.core/+ 1 1)
(println "~(+ 1 1) -> " `~(+ 1 1)) --> 2
(println "~'(+ 1 1) -> " `~'(+ 1 1)) --> (+ 1 1)
)
The last line was what I wanted. The first line was what I was getting.
If you escape a function then do not escape any parameters you want escaped. For instance, here we want
to call the "str" function at macro expand time and to expand the variable "hlq" to it's value 'vt:
;; this works
f1 `(quote (defun ~(str hlq "-inc") ~hlq (n) (+ n 1)))
;; doesn't work if you escape the hlq:
f1 `(quote (defun ~(str ~hlq "-inc") ~hlq (n) (+ n 1)))
I guess an escape spans to everything in the unit your escaping. Typically you escape atoms (like strings or symbols), but if it's a list then everything in the list is automatically escaped as well, so don't double escape.
4) FWIW, I ended writing a regex solution before I got the final answer. It's definitely not as nice:
(defn vt-gen-3 []
(let [hlq "vt"]
(let
[
f0 'list
f1 `(quote (defun ~(symbol (str hlq "-inc")) (n) (+ n 1)))
f2 '(quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8))))
]
`(~f0 ~f1 ~f2)
))
)
;; this strips out any qualifiers like "casc-gen.core/"
(defn vt-gen-3-regex []
(clojure.string/replace (str (vt-gen-3)) #"([\( ])([a-zA-Z0-9-\.]+\/)" "$1" ))
Macro expansion is very delicate and requires lots of practice.

clojure macro - don't know how to create ISeq from: clojure.lang.Symbol

I'm experimenting with clojure macros, and wondered what I might be doing wrong?
I have a simple example, of attempting to dynamically create functions based on a map.
For example:
(def units {:cm 100
:mm 1000
:m 1
:km 1/1000})
(defn m-to-unit-helper [[k v]]
(let [f (symbol (str "to-" (name k)))]
`(defn ~f [m#] (* ~v m#))))
(defmacro m-to-units [units-map]
(let [funcs (map m-to-unit-helper units-map)]
`(do ~#funcs)))
; complains with: Don't know how to create ISeq from: clojure.lang.Symbol
(m-to-units units)
; To try and debug
(defn debug [units-map]
(let [funcs (map m-to-unit-helper units-map)]
(clojure.pprint/pprint `(do ~#funcs))))
; see below
(debug units)
The macro doesn't work, but the debug output look like it should create the correct structure:
(do
(clojure.core/defn
to-mm
[m__32709__auto__]
(clojure.core/* 1000 m__32709__auto__))
(clojure.core/defn
to-m
[m__32709__auto__]
(clojure.core/* 1 m__32709__auto__))
(clojure.core/defn
to-cm
[m__32709__auto__]
(clojure.core/* 100 m__32709__auto__))
(clojure.core/defn
to-km
[m__32709__auto__]
(clojure.core/* 1/1000 m__32709__auto__)))
Any advice would be greatly appreciated. Thanks.
m-to-units is a macro which means that every parameter will be passed without being evaluated, meaning that inside the macro the value of units-map is actually the symbol units.
Now, if you pass the the map directly, it'll work as intended:
(m-to-units {:mm 1000, :m 1, :cm 100, :km 1/1000})
;; => #'user/to-km
(to-cm 10)
;; => 1000
What you could do - although I'd consider it bad practice - is using eval to get the actual value of the units map, no matter whether it's passed as a map or via a symbol:
(defmacro m-to-units
[units-map]
(let [funcs (map m-to-unit-helper (eval units-map))]
`(do ~#funcs)))
(m-to-units units)
;; => #'user/to-km

Why isn't this clojure function executing?

I'm working through some clojure examples from braveclojure:
http://www.braveclojure.com/writing-macros/
Currently I am trying to execute this
(ns turtle (:use clojure.pprint))
(def criticisms {:good "good code:" :bad "bad code:"})
(defn criticize-code
[[critkey code]]
`(println (~critkey criticisms) (quote ~code)))
(defmacro code-critic
[code-evaluations]
`(do ~#(map criticize-code code-evaluations)))
(println "executed code critic")
(code-critic {:good (+ 1 1) :bad (1 + 1)})
(println "code critic expansion")
(pprint (macroexpand '(code-critic {:good (+ 1 1) :bad (1 + 1)})))
;why isn't this executing?
(println "criticize code expansion")
(criticize-code [:good '(+ 1 1)])
Basically, I can verify that criticize-code returns properly formatted code through println; but I cannot actually execute it...can someone please tell me what I'm doing wrong?
Thank you!
The function criticize-code is being invoked. The quasi-quote, `, in the body of the function is a reader macro for syntax-quote, which means the following println form, after its trip through the syntax-quote reader, will be returned as data structure rather than executed. The criticize-code function is semantically equivalent to
(defn criticize-code
[[critkey code]]
(list
'clojure.core/println
(list critkey 'turtle/criticisms)
(list 'quote code)))
If you want to treat the resulting data structure as code at the REPL, you can eval it directly.
turtle=> (criticize-code [:good '(+ 1 1)])
(clojure.core/println (:good turtle/criticisms) (quote (+ 1 1)))
turtle=> (eval (criticize-code [:good '(+ 1 1)]))
good code: (+ 1 1)
nil
So why would you want a function that works like this? As a helper to a macro, as here for code-critic. Macros deal with code-as-data-as-code. Therefore, if you stick in a helper function at the as-data stage, it will need to return its result as data. Otherwise, the code you want to be compiled is just executed at "compile" time with its return value (println returns nil) compiled instead.

Clojure Nested Macro

Is it possible to macro returned macro? I would like to simplify the code maximum, and I can do this using a macro that returns the function. However, it is too much overhead and it is too slow. To keep the code more readable, I did not use type hints, but even with them my code is ~ 5x slower.
My English is not very precise, so I write what I have and what I wanted to have.
I have this...
(defmacro series [java-array]
`(fn
([i#]
(aget ~java-array i#))
([start# stop#]
(let [limit# (unchecked-subtract-int stop# start#)
result# (double-array limit#)]
(loop [i# 0]
(if (< i# limit#)
(let [r# (double (aget ~java-array i#))]
(aset result# i# r#)
(recur (inc i#)))
result#))))))
I want something like this...
(defmacro series [java-array]
`(defmacro blabla
([i#]
`(aget ~~java-array i#))
([start# stop#]
`(let [limit# (unchecked-subtract-int stop# start#)
result# (double-array limit#)]
(loop [i# 0]
(if (< i# limit#)
(let [r# (double (aget ~~java-array i#))]
(aset result# i# r#)
(recur (inc i#)))
result#))))))
But when I call this...
Wrong number of args (1) passed to: blabla
A simpler example.
I have a lot of java arrays. I do not want to use aget. I want macro to expand to (aget array-name i). I write a macro that expand to (fn [n] (aget array-name i)), but this is unnecessary overhead.
(defmacro series [arr]
`(fn [i#]
(aget (longs ~arr) (int i#))))
I now declare the series, such as "date", and call it in this way (date i), which will return me "i" element of the array.
I think what you're looking for is a way to declare local macros within functions. The clojure.tools.macro package has a macrolet form, which I think you should be able to wrangle into creating a macro for local array lookups.
Here's a little example I put together:
; project.clj
(defproject testproject "1.0.0-SNAPSHOT"
:description "FIXME: write description"
:dependencies [[org.clojure/clojure "1.5.0"]
[org.clojure/tools.macro "0.1.2"]])
; src/testproject/core.clj
(ns testproject.core
(:require [clojure.tools.macro :refer [macrolet]]))
(defn my-test []
(let [n 1000
arr (int-array n (range 10))]
(macrolet [(lookup [i] (list `aget 'arr i))]
(loop [i 0, acc 0]
(if (< i n)
(recur (inc i) (+ acc (lookup i)))
acc)))))
In the example I use macrolet to declare a macro called lookup that will cause (lookup 5) to expand into (lookup arr 5), which is what I think you're looking for.
Notice how you have to be careful when referencing arr from within the local macro definition. If you just declared the macro as`(aget arr ~i), then it tries to find a fully-qualified symbol arr, which doesn't exist. You could alternatively declare the macro as `(aget ~'arr ~i), but I felt that (list `aget 'arr i) looked a lot nicer.
Now you can take it one step further and use defmacro to create a macro that includes macrolet inside, which you can use to simplify the declaration of arrays with a local lookup macro. We leave this as an exercise for the reader.
Since macros are so subtle, and nesting macros in macros only makes things worse, I decided it would probably be more helpful to just give an example and let you figure out how it works:
(defmacro lookup-binding [[fn-sym value] & body]
(let [array-sym (symbol (str fn-sym "-raw"))]
`(let [~array-sym ~value]
(macrolet [(~fn-sym [i#] (list aget '~array-sym i#))]
~#body))))
(defn my-test2 []
(let [n 1000]
(lookup-binding [arr (int-array n (range 10))]
(loop [i 0, acc 0]
(if (< i n)
(recur (inc i) (+ acc (arr i)))
acc)))))
Disclaimer: I'm only trying to show that this is possible, not that it's a good idea. I personally don't think all this extra complexity is worth avoiding aget. I'd suggest just using aget since it's only a few extra characters, and it will make your code more clear/readable.

I don't know how lisp macro construct its expansion? what's the exact step?

I tried to write a macro and execute it as follow. but it failed to execute.
(defmacro times_two (var) (* 2 var))
(times_two '(+ 1 2))
In my imagination, I think the expansion would be (* 2 (+ 1 2)). and after execution, the result would be 6. But failed.
I don't know why. I read the Emacs lisp manual, but I still can't understand them. I want to know what on earth the exact steps is while constructing expansion. What did the interpreter do?
When I evaluate these forms in Emacs, I get this error message when evaluating the second one:
Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p (quote (+ 1 2)))
*(2 (quote (+ 1 2)))
(lambda (var) (* 2 var))((quote (+ 1 2)))
(times_two (quote (+ 1 2)))
eval((times_two (quote (+ 1 2))))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
call-interactively(eval-last-sexp nil nil)
This is showing you how it expanded the macro, which should tell you what went wrong. (The final expansion is at the top.)
The quoted expression '(+ 1 2) gets passed to the times_two macro, but a quoted list is not a valid argument to the * function.
What you actually want here is:
(defmacro times_two (var) `(* 2 ,var))
(times_two (+ 1 2))
Keep in mind that, generally, the result of a macro will be new Lisp code, not a final value. Your goal in writing a macro is to construct the form that will give you the result you want. Thus, most of the time your macro will end up using the quasiquote (`) syntax.
I suspect that you're confusing compile-time and run-time. Macros run at compile time, producing code to be executed at run-time. Generally speaking it's hard to keep these straight and it makes writing macros difficult.
In any event, when I put this into ielm, I get:
ELISP> (defmacro times_two (var)
(* 2 var))
times_two
ELISP> (times_two '(+ 1 2))
*** Eval error *** Wrong type argument: number-or-marker-p, (quote (+ 1 2))
ELISP>
At least part of the problem then is the '(+ 1 2), but then when I remove the quote the following is no better:
ELISP> (times_two (+ 1 2))
*** Eval error *** Wrong type argument: number-or-marker-p, (+ 1 2)
ELISP>
It seems that elisp is looking for a number or a marker in the place where we are putting '(+ 1 2) and (+ 1 2). Let's try using a number:
ELISP> (times_two 3)
6
That works.
Interestingly, the macro expansion of this gives:
ELISP> (macroexpand '(times_two 3))
6
Which is probably not really what we want.
When we write macros we want to return expressions to be evaluated at run time. So rather than returning a number we can try this:
ELISP> (defmacro times_two (var)
`(* 2 ,var))
The backtick (quasiquote) is a way of creating a list, but also allowing interpolation with the use of a comma. Defining times_two in this way gives:
ELISP> (times_two (+ 1 2))
6
And the expansion of:
ELISP> (macroexpand '(times_two (+ 1 2)))
(* 2
(+ 1 2))
Which is exactly how you imagined it.