Fork me on GitHub
#beginners
<
2018-05-10
>
denisgrebennicov09: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 🙄 Challenge link: https://www.hackerrank.com/challenges/brainf-k-interpreter-fp/problem Code link: https://github.com/denis631/-Hackerrank-BrainF__k-interpreter/blob/master/src/brainfuck_interpreter/core.clj

bronsa12:05:10

@denisgrebennicov that's the usual way to do it

deg13:05:11

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?

denisgrebennicov13:05:06

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

xlevus15:05:55

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# [email protected]] (with-options options# (~name [email protected])))
     ([[email protected]] [email protected])))
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.

xlevus15:05:04

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

alexmiller15: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

alexmiller15: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

alexmiller15:05:08

lucky for you, defn already has a spec!

xlevus15:05:39

oh what. defn is a function.

alexmiller15:05:59

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

xlevus15:05:50

https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L292 looks pretty functioney here? or is the (. (var defn) (setMacro)) the special sauce?

alexmiller15:05:13

macros are functions with a meta flag

alexmiller15:05:53

that flag tells the compiler to expand rather than invoke

alexmiller15: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)

alexmiller15:05:51

defmacro is itself … a macro

alexmiller15:05:31

anyhow, I digress

alexmiller15:05:03

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

alexmiller15: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)]]}]}

alexmiller15: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)

alexmiller15:05:14

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

alexmiller15: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

wushee16:05:21

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

lee.justin.m21:05:52

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?

malik08321:05:41

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

malik08321:05:05

@lee.justin.m thank you!