Fork me on GitHub
#cljs-dev
<
2019-01-11
>
souenzzo01:01:01

Is it a know bug/limitation? (works on clojure, but not in clojurescript) I searched in jira but I did not find anything. In cljs throws Can't recur here at line 1 <cljs repl> {:file "<cljs repl>", :line 1, :column 73, :root-source-info {:source-type :fragment, :source-form (myloop [] (recur))}, :tag :cljs/analysis-error}

clj -Srepro -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.10.0"} org.clojure/clojurescript {:mvn/version "1.10.439"}}}' -m cljs.main --repl-env node -e '(defmacro myloop [bindings & body] `(loop ~bindings ~@body)) (myloop [] (recur))'

mfikes01:01:29

@souenzzo You aren't getting a macro, but a function there. So, in Clojure it would essentially be like

user=> (defn foo [x & y] 1)
#'user/foo
user=> (foo [] (recur))
Syntax error (UnsupportedOperationException) compiling recur at (REPL:1:9).
Can only recur from tail position

mfikes01:01:58

TL;DR macros need to be defined in a different namespace and required

👍 5
petterik07:01:59

I don't know if this is a good idea, but I started thinking "what if clojure.core.protocols/coll-reduce was extendable via metadata"? All the sequence functions in core - when used in a reduce - could get called as transducers. Allowing us to write code that nest sequence functions instead of explicitly calling functions that take transducers, and still get the benefits of transducers...? See this implementation of map:

(defn map
  ([f]
    ;; transducer implementation
   )
  ([f coll]
   (with-meta
     (lazy-seq
      (when-let [s (seq coll)]
        (cons (f (first s)) (map f (rest s)))))
     ;; Implementing coll-reduce via metadata.
     {`p/coll-reduce
      (fn [_ rf init]
        (reduce ((map f) rf) init coll))})))
Implementing coll-reduce would look similarly for filter, partition, et. al. Now think about the how the code (reduce + 0 (map inc (filter even? (range 10)))) would get called. More on this in the thread.

petterik07:01:07

The transducers would compose. Example: The form: (reduce + 0 (map inc (filter even? (range 10)))) would reduce over the collection returned from range as: reduce would call coll-reduce on the value returned from map via metadata, -> map's reduce call would call coll-reduce on value returned from filter via metadata, -> filter's reduce call would call reduce on the coll (range 10).

petterik07:01:06

I don't know if there's any real performance gain here, but it should avoid allocating all the extra collections when they are being reduced over. It'd be fun to test this against the coal-mine :man-shrugging:

petterik07:01:23

I find the coll-reduce version of concat oddly satisfying for some reason 🙂

(defn concat
  ([])
  ([x])
  ([x y])
  ([x y & zs]
   (let [cat-fn (fn [xys zs]
                  ;;; cat impl..
                  )]
     (with-meta
       (cat-fn (concat x y) zs)
       ;; implementing concat with reduce
       {`p/coll-reduce
        (fn [_ rf init]
          (reduce (cat rf) init [x y (eduction cat zs)]))}))))

Alex Miller (Clojure team)13:01:10

I think reduce is too performance-sensitive to use the metadata extension

petterik15:01:16

^ That's what I wonder too, whether adding the ability to implement coll-reduce via metadata would decrease performance too much.

Alex Miller (Clojure team)15:01:07

you’re just taking the generic seq implementation that already exists in coll-reduce and copying it over N functions with a slower dispatch mechanism

Alex Miller (Clojure team)15:01:23

that seems worse in two dimensions

Alex Miller (Clojure team)15:01:13

well I guess it’s not the same implementation since you’re using the transducer

👍 5
Alex Miller (Clojure team)15:01:16

but I think you’re changing how the system works in ways that could be subtly surprising

💯 5
petterik16:01:01

The examples really helped me understand what this meant. Nice! I think there's a typo in this sentence:

meaning that the either a number of nil can be returned.
where it should be "number or nil", instead of "of". And remove the "the", making it:
meaning that either a number or nil can be returned.

dnolen13:01:50

@petterik it's interesting, but perhaps doesn't really add that much?

💯 5
petterik15:01:16

I totally agree. I might test it out at some point to see if there are any gains. Just figured I'd share it :man-shrugging: