Fork me on GitHub
Ashley Smith14:08:58

Hey everyone! So I want to compile my cljs code on the command line and output it to a specific file, but I'm struggling to find the command among the documentation. I was looking at this file, but it doesn't actually say what file these options go into? Does it go into my deps.edn somewhere? I have a dev.cljs.edn that figwheel uses, maybe it goes into there? I use figwheel for development but I'm tinkering with docker a bit today and I want to compile it without the figwheel stuff sometimes 🙂


@ashley If you are using plain cljs.main on the command line, see -co here

Ashley Smith15:08:55

I don't actually know how to invoke cljs.main - I only have clojure, cljs.main gives 'command not found cljs.main` @mfikes


any users of compojure-api? I'm using spec to build my swagger schemas and I can't use anonymous functions inside my specs. For example, (s/def ::value (s/and int? #(> % 10))) returns

  "type": "unknown-exception",
  "class": "java.lang.ClassCastException"


I'm trying to debug this error, and I got the following message:

  "message": "clojure.lang.MapEntry cannot be cast to java.lang.Number",
  "type": "unkown"


there are any special notation I should consider?


@ashley To run using cljs.main you do clojure -m cljs.main and then subsequent arguments follow that

Ashley Smith15:08:42

$ cat target/public/js/space.js 
var CLOSURE_UNCOMPILED_DEFINES = {"figwheel.repl.connect_url":"ws:\/\/localhost:8080\/figwheel-connect?fwprocess=451d5d&fwbuild=dev"};
var CLOSURE_NO_DEPS = true;
if(typeof goog == "undefined") document.write('<script src="/cljs-out/dev/goog/base.js"></script>');
document.write('<script src="/cljs-out/dev/goog/deps.js"></script>');
document.write('<script src="/cljs-out/dev/cljs_deps.js"></script>');
document.write('<script>if (typeof goog == "undefined") console.warn("ClojureScript could not load :main, did you forget to specify :asset-path?");</script>');
I give in, I tried getting things to work but it produced a js file with this

Ashley Smith15:08:53

$ clojure -m cljs.main -c -o target/public/js/space.js

Ashley Smith15:08:56

that is what I ran


Two comments: - -o is an init opt and -c is a main opt. Init opts must precede main opts. - if you want to have a self-contained outpost file, you’d need to specify that the compiler use optimizations of :whitespace or more (the default is :none which is meant for REPL use)

Ashley Smith17:08:37

hmm okay, let me give it another try

Ashley Smith17:08:25

I think i got it!

Ashley Smith17:08:33

It compiled a good file that looks correct

Ashley Smith17:08:54

now I just need to serve it, as the JS file it outputs to doesn't seem to be picked up by the website

Ashley Smith17:08:28

$ clojure -m This the command to start the server that should serve the javascript, and while it can find my index.html from resources/public/index.html, it cannot find my js file from target/public/js/space.js

Ashley Smith17:08:48

don't know how figwheel main managed to include that when the site starts

Ashley Smith18:08:10

I think I need to include the JS file through the actual server code and not build. Thank you!

Ashley Smith18:08:22

no I don't think its a cljs problem anymore, my js file seems to be output just fine 🙂


(There is a -s / --serve option.)


Right, you do t need to use cljs.main to serve the file if you have an actual server to serve it from.


I have this ("WWWWW" "BB" "BBBB" "W") how can i turn it in this ("5W" "2B" "4B" "W")?


user=> (map (fn [[k v]] (str (if (= k 1) "" k) (ffirst v))) (group-by count a))
("5W" "2B" "4B" "W")


@schmee What will that do for ["WW" "BB" "CC"]?


Works, thank you schmee


A: you get ("2W") so that solution won't work for general sequences.


right you are @U04V70XH6! here’s an updated solution:

(defn foo [things]
    (fn [[k vs]]
        #(str (if (= k 1) "" k) (first %))
    (group-by count things)))

user=> (foo '("WWWWW" "BB" "BBBB" "W" "AA" "BB" "CC"))
("5W" "2B" "2A" "2B" "2C" "4B" "W")

thanks for pointing it out! :thumbsup:


That's overly complicated. You don't need conditionals or nested maps for this.


your version prints “1W” instead of “W”, if that’s ok then I agree that you don’t need conditionals


but yeah, your juxt version is really slick 🙂


Oh, I missed that he didn't want a count on single letters. Sorry.

👍 1

Yeah, so a conditional is needed. I'd do that with another map in the transducer version.


yeah, group-by is for sure not needed at least 😄


(map (fn [[n c :as pair]] (if (= n 1) [c] pair)))


Someone should post a solution leveraging cl-format to hide the conditional

😂 1

Hahaha... I figured there would probably be some way to do it without a conditional!


@mouhieddinesabir Try this

user=> (into [] (comp (map (juxt count first)) (map #(apply str %))) a)
["2W" "2B" "2C"]
user=> (def a '("WWWWW" "BB" "BBBB" "W"))
user=> (into [] (comp (map (juxt count first)) (map #(apply str %))) a)
["5W" "2B" "4B" "1W"]


Or this, if you find it more natural (without the transducer so it's not as efficient):

user=> (def a '("WWWWW" "BB" "BBBB" "W"))
user=> (->> a (map (juxt count first)) (map #(apply str %)))
("5W" "2B" "4B" "1W")
user=> (def a ["WW" "BB" "CC"])
user=> (->> a (map (juxt count first)) (map #(apply str %)))
("2W" "2B" "2C")

👍 1
Lennart Buit20:08:06

juxt is really a delightful function


@schmee pointed out you wanted "W" for the single letter case so I'd need an extra little transformation in my suggestion

user=> (into [] (comp (map (juxt count first)) 
                      (map (fn [[n c :as pair]] (if (= 1 n) [c] pair))) 
                      (map #(apply str %))) a)
["5W" "2B" "4B" "W"]

👍 2

I have a nested map and I wish to convert all values in this map that are keyword into nil


could not find a way to perform that easily =/


(clojure.walk/walk (fn [[k v :as m]] (if (keyword? v) [k nil] m)) identity {:valor 10 :teste :v})


this is a very nice and useful namespace 🙂


yes was gonna say use a pre/postwalk!


that walk function doesn’t work for nested maps though


that's true, just tested


I’m sure it’s possible to make it work with clojure.walk, here is a Specter solution just for fun:

(def recurse-maps
  (recursive-path [] p
    (if-path map?
      [MAP-VALS p]

user=> (setval [recurse-maps keyword?] nil {:a :b :c 1 :d {:a :b :c 1 :d {:a nil :b :c}}})
{:a nil, :c 1, :d {:a nil, :c 1, :d {:a nil, :b nil}}}


This works on nested forms with clojure walk


one more function to my collection, map-entry? was the one missing on my implementation with postwalk

bartuka22:08:21 I just noticed that postwalk-replace has a different behavior on records


(clojure.walk/postwalk-replace {:veri :replaced} (->Teste "foo" "bar" "baz"))
;; => #...Teste{:veri "foo", :wand "bar", :clj "baz", :replaced "foo"}
(clojure.walk/postwalk-replace {:veri :replaced} {:veri "foo" :wand "bar" :clj "baz"})
;; => {:replaced "foo", :wand "bar", :clj "baz"}

Val Baca22:08:48

Hi all, I'm new here and new to clojure. Quick question: I have a function that takes a position {:dir :NORTH :x 0 :y 0} and an instruction "R10" (which means turn Right, then go 10 units) and then returns a new position, like {:dir EAST :x 10 :y 0}

(defn move
  "Given a pos (dir, x, y) and move instruction, returns a new pos"
  [pos inst]
  (apply-delta (assoc pos :dir (turn pos inst)) inst))
All of that is working just fine 🙂 But now I want to start with a single position, and a sequence of directions, like ["R10", "L20", "R10"] and know what the end position is. So in imperative pseudocode I want to do:
var pos = {:dir :NORTH :x 0 :y 0}
for (var dir : directions) {
    pos = move(pos, dir)
return pos
But I just can't seem to wrap my head around what that looks like in clojure. I understand reduce and map with single variables, but iterating over a list with a variable isn't really clicking.


(reduce move initial-position directions) is what it would look like most likely


reduce is often useful in cases like this.


(slack crashed and i wasn't sure it had posted)

Val Baca22:08:00

That did it! funny that's what I think I originally typed and said "nah, that's too easy" 😄


if you want a "path" look into reductions

Val Baca22:08:55

Thanks. It's on my "to study" list. One more question: I'm trying to figure out how to best use -> and ->> when the return value of one expression needs to be the first variable of the next expression: So for something like: (str/split (str/trim (slurp "resources/input01.txt")) #", ")) is there a preferred way to have this read left-to-right?

Val Baca22:08:47

oh actually, that one's easier since it's always the first, I can just use ->, what about when it isn't always the first parameter?


they can compose

(-> 1
    (vector 2)
    (->> (str/join ","))) ;; => "1,2"
there's also as-> that can be helpful at times

Val Baca22:08:47

Thank you again 🙂