I'm playing with function specs and I'm wondering if one could use it to emulate compile-type checking?
Macros are evaluated at compile time, so if I could do something like this:
(:require [clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as st])
(s/fdef divide
:args (s/cat :x integer? :y integer?)
:ret number?)
(defn divide [x y] (/ x y))
(st/instrument `divide)
(defmacro typed-divide [arg1 arg2]
(eval `(divide ~arg1 ~arg2)))
;; this should fail to compile?
(defn typed-divide-by-foo [arg]
(typed-divide arg :foo))
Although there might be some trick with macro system, your'd better to just write unit tests for that. Compile-time errors are quite vague and prevent REPL from being started. Instead, tests handle exceptions as well and collect nice reports when something goes wrong.
It's also not a good idea to instrument a function in production because it really slows down its performance. Instrument them only in tests. See example below:
(ns project.tests
(:require [clojure.test :refer :all]
[project.code :refer [divide]]))
;; here, in test namespace, you instrument a function
;; you'd like to test
(st/instrument `divide)
;; and then add a test
(deftest test-divide
(is (= (divide 6 2) 3)))
now, run the tests:
lein test
Related
I am trying to figure out core.async in my REPL and am completely confused as to how my usage of (go-loop ...) doesn't manage to qualify as a "go block" for the purpose of async/>!
My go-loop is like...
(async/go-loop [page (range 3)]
(if (empty? page)
(async/close! ch)
(dorun (map (fn [row]
(println row)
(async/>! ch row)) page)))
(recur (range (dec (count page)))))
But the REPL is all upset...
=>
#object[clojure.core.async.impl.channels.ManyToManyChannel
0x23465937
"clojure.core.async.impl.channels.ManyToManyChannel#23465937"]
0
Exception in thread "async-dispatch-12" java.lang.AssertionError: Assert failed: >! used not in (go ...) block
nil
...
Why isn't the scope of that (go-loop ...) sufficient for the (async/>! row) call?
Should I even be using a go-loop here?
>! and other parking calls can't be used inside of functions nested inside of a go unfortunately.
go turns the code you give it into a state machine and looks for parking calls. It doesn't however look inside of nested functions.
From Clojure.Asyncs Github best practice page:
Unsupported constructs and other limitations in go blocks
The go macro stops translating at function creation boundaries. This means the following code will fail to compile, or may just throw a runtime error stating that <! was used outside of a go block:
(go (let [my-fn (fn [] (<! c))]
(my-fn)))
This is one thing to remember since many Clojure constructs create functions inside macros. The following are examples of code that will not work as one would expect:
(go (map <! some-chan))
(go (for [x xs]
(<! x)))
Is there a reasonable way to have multiple def statements happen with destructing the same way that let does it? For Example:
(let [[rtgs pcts] (->> (sort-by second row)
(apply map vector))]
.....)
What I want is something like:
(defs [rtgs pcts] (->> (sort-by second row)
(apply map vector)))
This comes up a lot in the REPL, notebooks and when debugging. Seriously feels like a missing feature so I'd like guidance on one of:
This exists already and I'm missing it
This is a bad idea because... (variable capture?, un-idiomatic?, Rich said so?)
It's just un-needed and I must be suffering from withdrawals from an evil language. (same as: don't mess up our language with your macros)
A super short experiment give me something like:
(defmacro def2 [[name1 name2] form]
`(let [[ret1# ret2#] ~form]
(do (def ~name1 ret1#)
(def ~name2 ret2#))))
And this works as in:
(def2 [three five] ((juxt dec inc) 4))
three ;; => 3
five ;; => 5
Of course and "industrial strength" version of that macro might be:
checking that number of names matches the number of inputs. (return from form)
recursive call to handle more names (can I do that in a macro like this?)
While I agree with Josh that you probably shouldn't have this running in production, I don't see any harm in having it as a convenience at the repl (in fact I think I'll copy this into my debug-repl kitchen-sink library).
I enjoy writing macros (although they're usually not needed) so I whipped up an implementation. It accepts any binding form, like in let.
(I wrote this specs-first, but if you're on clojure < 1.9.0-alpha17, you can just remove the spec stuff and it'll work the same.)
(ns macro-fun
(:require
[clojure.spec.alpha :as s]
[clojure.core.specs.alpha :as core-specs]))
(s/fdef syms-in-binding
:args (s/cat :b ::core-specs/binding-form)
:ret (s/coll-of simple-symbol? :kind vector?))
(defn syms-in-binding
"Returns a vector of all symbols in a binding form."
[b]
(letfn [(step [acc coll]
(reduce (fn [acc x]
(cond (coll? x) (step acc x)
(symbol? x) (conj acc x)
:else acc))
acc, coll))]
(if (symbol? b) [b] (step [] b))))
(s/fdef defs
:args (s/cat :binding ::core-specs/binding-form, :body any?))
(defmacro defs
"Like def, but can take a binding form instead of a symbol to
destructure the results of the body.
Doesn't support docstrings or other metadata."
[binding body]
`(let [~binding ~body]
~#(for [sym (syms-in-binding binding)]
`(def ~sym ~sym))))
;; Usage
(defs {:keys [foo bar]} {:foo 42 :bar 36})
foo ;=> 42
bar ;=> 36
(defs [a b [c d]] [1 2 [3 4]])
[a b c d] ;=> [1 2 3 4]
(defs baz 42)
baz ;=> 42
About your REPL-driven development comment:
I don't have any experience with Ipython, but I'll give a brief explanation of my REPL workflow and you can maybe comment about any comparisons/contrasts with Ipython.
I never use my repl like a terminal, inputting a command and waiting for a reply. My editor supports (emacs, but any clojure editor should do) putting the cursor at the end of any s-expression and sending that to the repl, "printing" the result after the cursor.
I usually have a comment block in the file where I start working, just typing whatever and evaluating it. Then, when I'm reasonably happy with a result, I pull it out of the "repl-area" and into the "real-code".
(ns stuff.core)
;; Real code is here.
;; I make sure that this part always basically works,
;; ie. doesn't blow up when I evaluate the whole file
(defn foo-fn [x]
,,,)
(comment
;; Random experiments.
;; I usually delete this when I'm done with a coding session,
;; but I copy some forms into tests.
;; Sometimes I leave it for posterity though,
;; if I think it explains something well.
(def some-data [,,,])
;; Trying out foo-fn, maybe copy this into a test when I'm done.
(foo-fn some-data)
;; Half-finished other stuff.
(defn bar-fn [x] ,,,)
(keys 42) ; I wonder what happens if...
)
You can see an example of this in the clojure core source code.
The number of defs that any piece of clojure will have will vary per project, but I'd say that in general, defs are not often the result of some computation, let alone the result of a computation that needs to be destructured. More often defs are the starting point for some later computation that will depend on this value.
Usually functions are better for computing a value; and if the computation is expensive, then you can memoize the function. If you feel you really need this functionality, then by all means, use your macro -- that's one of the sellings points of clojure, namely, extensibility! But in general, if you feel you need this construct, consider the possibility that you're relying too much on global state.
Just to give some real examples, I just referenced my main project at work, which is probably 2K-3K lines of clojure, in about 20 namespaces. We have about 20 defs, most of which are marked private and among them, none are actually computing anything. We have things like:
(def path-prefix "/some-path")
(def zk-conn (atom nil))
(def success? #{200})
(def compile* (clojure.core.memoize/ttl compiler {} ...)))
(def ^:private nashorn-factory (NashornScriptEngineFactory.))
(def ^:private read-json (comp json/read-str ... ))
Defining functions (using comp and memoize), enumerations, state via atom -- but no real computation.
So I'd say, based on your bullet points above, this falls somewhere between 2 and 3: it's definitely not a common use case that's needed (you're the first person I've ever heard who wants this, so it's uncommon to me anyway); and the reason it's uncommon is because of what I said above, i.e., it may be a code smell that indicates reliance on too much global state, and hence, would not be very idiomatic.
One litmus test I have for much of my code is: if I pull this function out of this namespace and paste it into another, does it still work? Removing dependencies on external vars allows for easier testing and more modular code. Sometimes we need it though, so see what your requirements are and proceed accordingly. Best of luck!
Consider the following snippet:
(require '[clojure.core.async :refer :all])
(def my-chan (chan (buffer 10)))
(go (while true
(>! my-chan (rand))))
This basically provides a buffered channel, which always contains some 10 random numbers. When the channel is consumed, the buffer is filled again.
Is there an abstraction for this in core.async? As there are transducers for manipulating the consumption of channels, there might be something for the production of them as well:
For sequences one would go for something like this:
(def my-seq
(map (fn [_] (rand)) (range)))
or, just:
(def my-seq (repeatedly rand))
Which of course is not buffered, but it might give an idea of what I'm looking for.
Transducers don't manipulate the consumption of channels -- they affect the values, but they don't affect the consumption of the data on the channel.
You seem to be asking of a way to abstract the creation of a channel, and then get values off of it as a sequence. Here are some ideas, though I'm not convinced that core.async really offers anything above normal clojure.core functionality in this case.
Abstraction is done here the way it usually is done -- with functions. This will call f and put its result on the channel. The implication here is of course that f will be side-effecting, and impure, otherwise it would be quite a boring channel to consume from, with every value being identical.
(defn chan-factory
[f buf]
(let [c (chan buf)]
(go-loop []
(>! c (f))
(recur))
c))
If you then wanted to create a lazy sequence from this, you could do:
(defn chan-to-seq [c]
(lazy-seq
(cons (<!! c) (chan-to-seq c))))
Define your seq:
(def rand-from-chan (chan-to-seq (chan-factory rand 10)))
(take 5 rand-from-chan)
=>
(0.6873518531956767
0.6940302424998631
0.07293052906941855
0.7264083273536271
0.4670275072317531)
However, you can accomplish this same thing by doing:
(def rand-nums (repeatedly rand))
So, while what you're doing is a great thought experiment, it may be more helpful to find some concrete use cases, and then maybe you will receive more specific ideas. Good luck!
Probably obvious, but given this code (from http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/reify):
(defn reify-str []
(let [f "foo"]
(reify Object
(ToString [this] f))))
(defn -main [& args]
(println (reify-str))
(System.Console/ReadLine))
Why am I getting this output?
#<ui$reify_str$reify__4722__4727 foo>
Instead of:
foo
I'm running ClojureCLR in Windows, if it helps. Thanks!
Your basic problem is that the Clojure REPL uses print-method, not .toString. You have to define print-method for your type. It's a little bit annoying for reified types since it makes them kind of verbose. You'll have to do something like this:
(defn reify-str []
(let [f "foo"
r (reify Object
(ToString [this] f))]
(defmethod clojure.core/print-method (type r) [this writer]
(print-simple f writer))
r))
(I've only tested this in vanilla Clojure, but I think it's the same in ClojureCLR.)
At this point, though, you're almost better off creating an actual type instead of reifying, because you're redefining the method every time. (I guess you could do some sort of global state to avoid the necessity, but…well, you can see why defining a type might be preferable.)
When using ClojureScript I tried to define a function that is a closure over a variable like this:
(let [x 42]
(defn foo [n] (+ x n)))
That prints the following source at the Rhino REPL:
function foo(n){
return cljs.core._PLUS_.call(null,x__43,n);
}
The function works as I expect but when trying to get at the variable named x__43 I can't get it. Where did it go?
the x variable is defined outside the foo function, in the let binding. you can't "get it" because you're not in the scope of the let binding. that's more or less the whole point of using closures.
conceptually, let bindings are implemented as function calls:
(let [x 2] ...)
is equivalent to
((fn [x] ...) 2)
which is probably similar to let is implemented in ClojureScript - either as a macro transformation to fn or directly to (function(x){...})(2).
(let [x 42]
(defn foo [n] (+ x n)))
is currently compiled to
var x__1311 = 42;
cljs.user.foo = (function foo(n){
return (x__1311 + n);
});
The exact number attached to the x may of course vary from compilation to compilation and cljs.user would be replaced by the appropriate namespace name.
There is no attempt to conceal the generated variable from unrelated code in a JavaScript closure, so in principle it could still be modified if one went out of one's way to do so. Accidental collisions are extremely unlikely and simply will not happen with regular ClojureScript.
To discover things like the above, you can either call the compiler with {:optimizations :simple :pretty-print true} among the options or ask it to emit some JavaScript at the REPL (as provided by script/repl in the ClojureScript source tree or lein repl in a Leiningen project with ClojureScript declared as a dependency):
(require '[cljs.compiler :as comp])
(binding [comp/*cljs-ns* 'cljs.user]
(comp/emit
(comp/analyze {:ns {:name 'cljs.user} :context :statement :locals {}}
'(let [x 42] (defn foo [n] (+ x n))))))