ClojureScript Macro Gone Awry - clojure

Goal: I'm trying to make a macro which takes as an input something like the following:
(cb-chan (.readFile "/path/to/file" "utf8" _))
and returns as an output something like the following:
(go (let [c (chan 1)
rep (.readFile "path/to/file" "utf8" (>? c)] ; >? is a function that I defined elsewhere that jams the result of a callback into a channel
rep
(<! c))))
Notice that the _ in the original input is being replaced by special callback (defined elsewhere). This callback jams its result into a channel, which is then retrieved and returned at end of the go block.
Attempt:
(defmacro cb-chan [func]
`(cljs.core.async.macros/go
(let [~'c (cljs.core.async/chan 1)]
~'rep (replace (quote {~'_ (cljs-async-patterns.core/>? ~'c) }) (quote ~func))
~'rep
(~'<! ~'c))))
Result: This fails since rep is just ends up being a literal, unevaluated list. If I were able to type (eval rep) on the second to last line instead of just rep, my problem would be fixed, but I cannot since I'm working in ClojureScript (where there is no eval). How do I get around this?

first of all, what do you need is probably a bit different. look at your desired code
(go (let [c (chan 1)
rep (.readFile "path/to/file" "utf8" (>? c)]
rep
(<! c))))
do you really need to bind a var rep? what you want is probably this:
(go (let [c (chan 1)]
(.readFile "path/to/file" "utf8" (>? c)
(<! c))))
because there is no need for rep
however, you should consider rereading some articles about macros, because here you have a mess of random qoutes and unquotes.
the macro generating your code would look like this:
(defmacro cb-chan [func]
(let [c (gensym "c")]
`(cljs.core.async.macros/go
(let [~c (cljs.core.async/chan 1)
rep# ~(replace {'_ `(cljs-async-patterns.core/>? ~c)} func)]
rep#
(cljs.core.async/<! ~c)))))
it will expand (cb-chan (.readFile "/path/to/file" "utf8" _)) to this:
(cljs.core.async.macros/go
(let [c19307 (cljs.core.async/chan 1)
rep__19301__auto__ (.readFile
"/path/to/file"
"utf8"
(cljs-async-patterns.core/>? c19307))]
rep__19301__auto__
(cljs.core.async/<! c19307)))
for my variant (without rep):
(defmacro cb-chan [func]
(let [c (gensym "c")]
`(cljs.core.async.macros/go
(let [~c (cljs.core.async/chan 1)]
~(replace {'_ `(cljs-async-patterns.core/>? ~c)} func)
(cljs.core.async/<! ~c)))))
expands to:
(cljs.core.async.macros/go
(let [c19313 (cljs.core.async/chan 1)]
(.readFile
"/path/to/file"
"utf8"
(cljs-async-patterns.core/>? c19313))
(cljs.core.async/<! c19313)))

Related

Using channel in `case`

(let [a (clojure.core.async/chan)]
(case a
a :foo
:bar))
#=> :bar
I would expect :foo here. What am I doing wrong?
On the other hand (condp = chan ...) does the job.
PS:
Basically I am trying to do following thing:
(require '[clojure.core.async :as a])
(let [chan1 (a/chan 10)
chan2 (a/chan 10)]
(a/>!! chan1 true)
(let [[v c] (a/alts!! [chan1 chan2])]
(case c
chan1 :chan1
chan2 :chan2
:niether)))
#=> :neither
The docs for case have the answer
The test-constants are not evaluated. They must be compile-time
literals, and need not be quoted.
The correct solution is to use cond:
(let [chan1 (ca/chan 10)
chan2 (ca/chan 10)]
(ca/>!! chan1 true)
(let [[v c] (ca/alts!! [chan1 chan2])]
(spyx (cond
(= c chan1) :chan1
(= c chan2) :chan2
:else :neither))))
;=> :chan1
Case uses unevaluated test-constants for the left-hand-side of the clause. Plain symbols, like chan1 here will match only the symbol with the same name, not the value of the local binding with that name; chan1 will match 'chan1

How to write clojure conditional statements

How can one translate the following code
while ((readInteger = fileInputStream.read()) != -1) {
.....
}
in clojure ? I need the value of readInteger in further parts of the code but also the '!= -1' needs to take place inside the while conditional.
some general patterns for adapting things to the Clojure syntax
move the ( to the left of the function or opperator.
move opperators to the left of the things they work on and surround with ( )
so you could start like this:
(while (not= (.read fileInputStream) -1 ... and so on.
then, since you need to use the readInteger value later in the code let's talk about naming values and looping. If you just wanted to read a value once and give it a name you could do it like this:
(let [readInteger (.read fileInputStream)]
... your code here)
Since you want to do it in a loop, then let's use loop instead of let:
(loop [readInteger (.read fileInputStream)]
... your code here
(if (not= readInteger -1)
(recur (.read fileInputStream))))
or for (which is not the "for loop" from other languages)
(for [readInteger (repeatedly #(.read fileInputStream))
:while (not= readInteger -1)]
... do somethign with readInteger ...)
For generates sequences of results rather than just looping like it does in other languages.
Then the next step in clojuring is to think about how to split the reading the data from processing it. We can:
make a sequence of all the data
process each data
something like this:
(let [data (line-seq fileInputStream)]
(map #(Integer/parseInt %) data)
...)
There are functions in the standard library for converting a great many things into sequences, and a bunch of functions for doing a great many things with sequences.
Don't solve this problem with while, which requires you to do your test at the beginning of the loop. Instead, think about a recursive function, which can decide at any part of its body whether to make the recursive call or not. Any iterative loop can be converted into a tail-recursive function using loop/recur; here's an example of how to do it with your loop.
(loop []
(let [read-integer (.read file-input-stream)]
(when (not= read-integer -1)
(...)
(recur))))
Here are two similar examples like amalloy suggested:
(ns xyz...
(:require [clojure.java.io :as io] )
(:import [java.io StringReader] ))
(newline) (newline)
(let [reader-2 (io/reader (StringReader. "first")) ]
(loop []
(let [curr-char-int (.read reader-2)]
(when (not= -1 curr-char-int)
(print (char curr-char-int) " ")
(recur)))))
(newline) (newline)
(let [reader-2 (io/reader (StringReader. "second")) ]
(loop [curr-char-int (.read reader-2)]
(when (not= -1 curr-char-int)
(print (char curr-char-int) " ")
(recur (.read reader-2)))))
With result:
> lein run
f i r s t
s e c o n d
In the first case it takes an extra let statement, but doesn't duplicate the part (.read reader-2) like the 2nd case does.
Using threading macro:
(->> (repeatedly #(.read fs))
(take-while (partial not= -1))
(map str))
Replace (map str) with whatever function you want to operate
on the stream. For example, to calculate the sum:
(->> (repeatedly #(.read fs))
(take-while (partial not= -1))
(reduce +))

Clojure macros: quoting, unquoting and evaluation

I have the following code:
(ns macroo)
(def primitives #{::byte ::short ::int})
(defn primitive? [type]
(contains? primitives type))
(def pp clojure.pprint/pprint)
(defn foo [buffer data schema]
(println schema))
(defmacro write-fn [buffer schema schemas]
(let [data (gensym)]
`(fn [~data]
~(cond
(primitive? schema) `(foo ~buffer ~data ~schema)
(vector? schema) (if (= ::some (first schema))
`(do (foo ~buffer (count ~data) ::short)
(map #((write-fn ~buffer ~(second schema) ~schemas) %)
~data))
`(do ~#(for [[i s] (map-indexed vector schema)]
((write-fn buffer s schemas) `(get ~data ~i)))))
:else [schema `(primitive? ~schema) (primitive? schema)])))) ; for debugging
(pp (clojure.walk/macroexpand-all '(write-fn 0 [::int ::int] 0)))
The problem is, upon evaluating the last expression, I get
=>
(fn*
([G__6506]
(do
[:macroo/int :macroo/int true false]
[:macroo/int :macroo/int true false])))
I'll explain the code if necessary, but for now i'll just state the problem (it might be just a newbie error I'm making):
`(primitive? ~schema)
and
(primitive? schema)
in the :else branch return true and false respectively, and since i'm using the second version in the cond expression, it fails where it shouldn't (I'd prefer the second version as it would be evaluated at compile time if i'm not mistaken).
I suspect it might have something to do with symbols being namespace qualified?
After some investigations (see edits), here is a working Clojure alternative. Basically, you rarely need recursive macros. If you
need to build forms recursively, delegate to auxiliary functions and call them from the macro (also, write-fn is not a good name).
(defmacro write-fn [buffer schemas fun]
;; we will evaluate "buffer" and "fun" only once
;; and we need gensym for intermediate variables.
(let [fsym (gensym)
bsym (gensym)]
;; define two mutually recursive function
;; to parse and build a map consisting of two keys
;;
;; - args is the argument list of the generated function
;; - body is a list of generated forms
;;
(letfn [(transformer [schema]
(cond
(primitive? schema)
(let [g (gensym)]
{:args g
:body `(~fsym ~schema ~bsym ~g)})
(sequential? schema)
(if (and(= (count schema) 2)
(= (first schema) ::some)
(primitive? (second schema)))
(let [g (gensym)]
{:args ['& g]
:body
`(doseq [i# ~g]
(~fsym ~(second schema) ~bsym i#))})
(reduce reducer {:args [] :body []} schema))
:else (throw (Exception. "Bad input"))))
(reducer [{:keys [args body]} schema]
(let [{arg :args code :body} (transformer schema)]
{:args (conj args arg)
:body (conj body code)}))]
(let [{:keys [args body]} (transformer schemas)]
`(let [~fsym ~fun
~bsym ~buffer]
(fn [~args] ~#body))))))
The macro takes a buffer (whatever it is), a schema as defined by your language and a function to be called for each value being visited by the generated function.
Example
(pp (macroexpand
'(write-fn 0
[::int [::some ::short] [::int ::short ::int]]
(fn [& more] (apply println more)))))
... produces the following:
(let*
[G__1178 (fn [& more] (apply println more)) G__1179 0]
(clojure.core/fn
[[G__1180 [& G__1181] [G__1182 G__1183 G__1184]]]
(G__1178 :macroo/int G__1179 G__1180)
(clojure.core/doseq
[i__1110__auto__ G__1181]
(G__1178 :macroo/short G__1179 i__1110__auto__))
[(G__1178 :macroo/int G__1179 G__1182)
(G__1178 :macroo/short G__1179 G__1183)
(G__1178 :macroo/int G__1179 G__1184)]))
First, evaluate buffer and fun and bind them to local variables
Return a closure which accept one argument and destructures it according to the given schema, thanks to Clojure's destructuring capabilities.
For each value, call fun with the appropriate arguments.
When the schema is [::some x], accept zero or more values as a vector and call the function fun for each of those values. This needs to be done with a loop, since the size is only know when calling the function.
If we pass the vector [32 [1 3 4 5 6 7] [2 55 1]] to the function generated by the above macroexpansion, the following is printed:
:macroo/int 0 32
:macroo/short 0 1
:macroo/short 0 3
:macroo/short 0 4
:macroo/short 0 5
:macroo/short 0 6
:macroo/short 0 7
:macroo/int 0 2
:macroo/short 0 55
:macroo/int 0 1
In this line:
`(do ~#(for [[i s] (map-indexed vector schema)]
((write-fn buffer s schemas) `(get ~data ~i)))))
you are calling write-fn, the macro, in your current scope, where s is just a symbol, not one of the entries in schema. Instead, you want to emit code that will run in the caller's scope:
`(do ~#(for [[i s] (map-indexed vector schema)]
`((write-fn ~buffer ~s ~schemas) (get ~data ~i)))))
And make a similar change to the other branch of the if, as well.
As an aside, it looks to me at first glance like this doesn't really need to be a macro, but could be a higher-order function instead: take in a schema or whatever, and return a function of data. My guess is you're doing it as a macro for performance, in which case I would counsel you to try it out the slow, easy way first; once you have that working you can make it a macro if necessary. Or, maybe I'm wrong and there's something in here that fundamentally has to be a macro.

How to model Rx's `withLatestFrom` with core.async channels?

For example given a channel with operations and another channel with data, how to write a go block that will apply the operation on whatever was the last value on the data channel?
(go-loop []
(let [op (<! op-ch)
data (<! data-ch)]
(put! result-ch (op data))))
Obviously that doesn't work because it would require both channels to have the same frequency.
(see http://rxmarbles.com/#withLatestFrom)
Using alts! you could accomplish what you want.
The with-latest-from shown below implements the same behavior found in the withLatestFrom from RxJS (I think :P).
(require '[clojure.core.async :as async])
(def op-ch (async/chan))
(def data-ch (async/chan))
(defn with-latest-from [chs f]
(let [result-ch (async/chan)
latest (vec (repeat (count chs) nil))
index (into {} (map vector chs (range)))]
(async/go-loop [latest latest]
(let [[value ch] (async/alts! chs)
latest (assoc latest (index ch) value)]
(when-not (some nil? latest)
(async/put! result-ch (apply f latest)))
(when value (recur latest))))
result-ch))
(def result-ch (with-latest-from [op-ch data-ch] str))
(async/go-loop []
(prn (async/<! result-ch))
(recur))
(async/put! op-ch :+)
;= true
(async/put! data-ch 1)
;= true
; ":+1"
(async/put! data-ch 2)
;= true
; ":+2"
(async/put! op-ch :-)
;= true
; ":-2"
There's an :priority true option for the alts!.
An expression which always returns the latest seen value in some channel would look something like this:
(def in-chan (chan))
(def mem (chan))
(go (let [[ch value] (alts! [in-chan mem] :priority true)]
(take! mem) ;; clear mem (take! is non-blocking)
(>! mem value) ;; put the new (or old) value in the mem
value ;; return a chan with the value in
It's untested, it's probably not efficient (a volatile variable is probably better). The go-block returns a channel with only the value, but the idea could be expanded to some "memoized" channel.

How do you convert a expression into a predicate? (Clojure)

Given that I have a expression of the form
'(map? %)
How do I convert it into something like
'#(map? %)
So that I can ultimately expand it into something like
'(apply #(map? %) value)
I think I should use a macro in some way, but am not sure how.
The # invokes a reader macro and reader macros expansion happen before normal macros expansion happens. So to do what you have mentioned, you need to go through the reader in your macro using read-string as shown below.
(defmacro pred [p v]
(let [s# (str \# (last p))]
`(apply ~(read-string s#) ~v)))
user=> (pred '(map? %) [{}])
true
user=> (pred '(map? %) [[]])
false
In case the data i.e the predicate expression is available at runtime then you need to use a function (which is more flexible then macro).
(defn pred [p v]
(let [s (read-string (str \# p))]
(eval `(apply ~s ~v))))
user=> (map #(pred % [12]) ['(map? %)'(even? %)])
(false true)
#(...) is a reader macro. I don't think that you can generate expression with reader macro. For example '#(map? %) will automatically expand into (fn* [p1__352#] (map? p1__352#)) or something similar.
Here's a somewhat relevant discussion on other reader macro.
Would it be possible to change format of the predicate? If it looked something like:
'([arg1] (map? arg1))
Then it would be trivial to make a function form it:
(cons 'fn '([arg1] (map? arg1)))
(def pred (eval (cons 'fn '([p](map? p)))))
#'predicate.core/pred
(pred {})
true
(pred 10)
false
Now please don't hate me for what I'm going to post next. I wrote an overly simplified version of the function reader macro:
(defn get-args [p]
(filter #(.matches (str %) "%\\d*")
(flatten p)))
(defn gen-args [p]
(into []
(into (sorted-set)
(get-args p))))
(defmacro simulate-reader [p]
(let [arglist (gen-args p)
p (if (= (str (first p)) "quote")
(second p)
p)]
(list 'fn (gen-args p) p)))
Using it is very straight-forward:
((simulate-reader '(map? %)) {}) ; -> true
; or without quote
((simulate-reader (map? %)) {})
; This also works:
((simulate-reader '(+ %1 %2)) 10 5) ; -> 15
The difference with the other solution given by #Ankur is:
I like mine less. I just thought it was a fun thing to do.
Does not require conversion to string and then applying reader macro to it.