Fork me on GitHub
Denis G09:05:14

Just implemented Brainfuck interpreter in Clojure 😄 Is there a smart way of doing ADTs other than dictionaries and creating multimethods which are dispatched by key? This is the way I did it :face_with_rolling_eyes: Challenge link: Code link:

👍 4

@denisgrebennicov that's the usual way to do it


After a long time in the CLJS world, I need to jump back to Clojure to create a simple server (mostly a wrapper around large existing Java libs, to deliver a REST API). What's the current best-practice set of libraries for this?

Denis G13:05:06

I guess it’s compojure, but don’t quote me on that


I've got a load of functions that take an optional first parameter, and then calls itself inside a binding. e.g.

(defn foo 
  ([opts a b c] (binding [*options* opts] (foo a b c)))
  ([a b c] (+ a b c)))
but it's a bit... repetitive, so I decided to write a macro, to do the binding for me
(defmacro defn-opts [name args & body]
  `(defn ~name
     ([options# ~@args] (with-options options# (~name ~@args)))
     ([~@args] ~@body)))
Works fine... Until my function has var-args. e.g.
(defn-opts vargs [& args] (count args))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: & in this context, compiling:(/tmp/form-init835293560141170332.clj:1:1)
but I'm finding it impossible to google a solution, because & isn't googleable. Is there a solution to this? I imagine it is as defn is a macro.


also, is there a way to support (optional?) docstrings in my macro like defn would? or do I need to rewrite most of defn?

Alex Miller (Clojure team)15:05:16

you would need to rewalk some of what defn does - both looking for and handling the special symbol & and determining whether the first arg is a string

Alex Miller (Clojure team)15:05:57

one way to do this would be to write a spec for the args and conform the arg list against the spec - this gives you a data structure describing how the args conform

Alex Miller (Clojure team)15:05:08

lucky for you, defn already has a spec!


oh what. defn is a function.

Alex Miller (Clojure team)15:05:59

defn is a macro and you can see it’s spec with (doc defn)

xlevus15:05:50 looks pretty functioney here? or is the (. (var defn) (setMacro)) the special sauce?

Alex Miller (Clojure team)15:05:13

macros are functions with a meta flag

Alex Miller (Clojure team)15:05:53

that flag tells the compiler to expand rather than invoke

Alex Miller (Clojure team)15:05:44

in this particular case, defn is being defined not with defmacro because defmacro has not yet been defined (as this is during bootstrap)

Alex Miller (Clojure team)15:05:51

defmacro is itself … a macro

Alex Miller (Clojure team)15:05:03

you can conform the args to a defn-like macro using the spec :clojure.core.specs.alpha/defn-args

Alex Miller (Clojure team)15:05:38

user=> (s/conform :clojure.core.specs.alpha/defn-args '[vargs [& args] (count args)])
{:name vargs, :bs [:arity-1 {:args {:varargs {:amp &, :form [:sym args]}}, :body [:body [(count args)]]}]}

Alex Miller (Clojure team)15:05:29

the defn spec knows how to parse the varargs out and break down the inputs. some code would be needed to decide how to transform this data structure into your macro output. That may or may not be harder than manipulating the incoming args directly (but keep in mind that the spec understand the full set of destructuring and nested destructuring that’s possible)

Alex Miller (Clojure team)15:05:14

user=> (pprint (s/conform :clojure.core.specs.alpha/defn-args '[vargs [{:keys [foo bar]} [[a b & c]] & args] (count args)]))
{:name vargs,
    [[:map {:keys [foo bar]}]
         {:elems [[:sym a] [:sym b]],
          :rest {:amp &, :form [:sym c]}}]]}]],
    :varargs {:amp &, :form [:sym args]}},
   :body [:body [(count args)]]}]}

Alex Miller (Clojure team)15:05:55

you should be able to actually manipulate that data structure too and then s/unform to get back to a “signature” but there is a known issue in this particular spec that the arg vectors will roundtrip back to lists instead


[a & b], & b is just a way of denoting rest parameters, correct?


i’m trying to write a clojurescript macro that expands to include a function call that is defined in my own code base. e.g.: i’m writing a macro in my-project/macros ns in a clojure file and i want the expanded macro to call a function in my-project/util, which is a cljs file. do i just hard code the namespace?


Hello, I am a beginner in Clojure with async.core. I was wondering if knew of any good resources regarded async especially with 'channels'.