Fork me on GitHub
#beginners
<
2019-08-03
>
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. https://clojurescript.org/reference/compiler-options 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 🙂

mfikes15:08:00

@ashley If you are using plain cljs.main on the command line, see -co here https://clojurescript.org/reference/repl-and-main

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

bartuka15:08:31

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"
}

bartuka16:08:37

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"
}

bartuka15:08:53

there are any special notation I should consider?

mfikes15:08:38

@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>');
document.write('<script>goog.require("figwheel.core");</script>');
document.write('<script>goog.require("figwheel.main");</script>');
document.write('<script>goog.require("figwheel.repl.preload");</script>');
document.write('<script>goog.require("devtools.preload");</script>');
document.write('<script>goog.require("figwheel.main.css_reload");</script>');
document.write('<script>goog.require("process.env");</script>');
document.write('<script>goog.require("space.site.cljs.core");</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 space.site.cljs.core -o target/public/js/space.js

Ashley Smith15:08:56

that is what I ran

mfikes17:08:37

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 space.site.clj.core 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 🙂

mfikes18:08:23

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

mfikes18:08:58

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

BIRSA19:08:37

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

schmee19:08:46

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

seancorfield20:08:14

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

BIRSA20:08:43

Works, thank you schmee

seancorfield20:08:02

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

schmee20:08:11

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

(defn foo [things]
  (mapcat
    (fn [[k vs]]
      (map
        #(str (if (= k 1) "" k) (first %))
        vs))
    (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:

seancorfield20:08:50

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

schmee20:08:11

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

schmee20:08:50

but yeah, your juxt version is really slick 🙂

seancorfield20:08:12

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

👍 1
seancorfield20:08:21

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

schmee20:08:39

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

seancorfield20:08:29

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

mfikes20:08:54

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

😂 1
seancorfield22:08:54

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

seancorfield20:08:23

@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/a
user=> (into [] (comp (map (juxt count first)) (map #(apply str %))) a)
["5W" "2B" "4B" "1W"]
user=>                

seancorfield20:08:00

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
user=> (->> a (map (juxt count first)) (map #(apply str %)))
("5W" "2B" "4B" "1W")
user=> (def a ["WW" "BB" "CC"])
#'user/a
user=> (->> a (map (juxt count first)) (map #(apply str %)))
("2W" "2B" "2C")
user=>     

👍 1
Lennart Buit20:08:06

juxt is really a delightful function

seancorfield20:08:11

@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"]
user=>

👍 2
bartuka21:08:46

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

bartuka21:08:03

could not find a way to perform that easily =/

bartuka21:08:36

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

bartuka21:08:28

this is a very nice and useful namespace 🙂

schmidt7321:08:50

yes was gonna say use a pre/postwalk!

schmee21:08:18

that walk function doesn’t work for nested maps though

bartuka21:08:15

that's true, just tested

schmee21:08:34

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]
      STAY)))

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}}}

schmidt7321:08:24

This works on nested forms with clojure walk

bartuka21:08:07

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

bartuka22:08:21

@henri.schmidt I just noticed that postwalk-replace has a different behavior on records

bartuka22:08:58

(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.

dpsutton22:08:08

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

andy.fingerhut22:08:14

reduce is often useful in cases like this.

dpsutton22:08:27

(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" 😄

dpsutton22:08:33

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?

dpsutton22:08:37

they can compose

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

Val Baca22:08:47

Thank you again 🙂