Fork me on GitHub
#beginners
<
2019-08-03
>
markgdawson07:08:48

Is there a way to set s default value for print-level and print-length in the REPL ? Can I put a config/startup script somewhere?

markgdawson07:08:48

Is there a way to set s default value for print-level and print-length in the REPL ? Can I put a config/startup script somewhere?

schmee08:08:50

what repl are you using? leiningen?

markgdawson13:08:17

I start through CIDER with emacs. The command line is something like this: [nREPL] Starting server via ~/.local/bin/lein update-in :dependencies conj \[nrepl\ \"0.6.0\"\] -- update-in :plugins conj \[cider/cider-nrepl\ \"0.22.0-beta4\"\] -- repl :headless :host localhost...

mafcocinco01:08:29

(set! *print-length* <integer>) will set the print length to the number you specify. Same call for *print-level*. You can also set either to nil in which case there will be no limit.

mafcocinco14:08:07

Totally missed the second part and did not at all answer your question. Sorry about that. I don't know of a really clean way to do it but there is a way. If you are using Leiningen, inside of the :repl-options map, there is a supported key called :init, which accepts any arbitrary Clojure form. You can find it in the Leiningen example project here: https://github.com/technomancy/leiningen/blob/stable/sample.project.clj#L372. You can add the code above to set the *print-length* to your project.clj (or potentially better in your .lein/profiles.clj, which will apply it globally across all projects) in this field, which should set the length you desire whenever you start the repl. I haven't tested this but I think it will work. I imagine Boot has a similar capability if you are using that instead of Leiningen.

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

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

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

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

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

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

ashley15:08:53

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

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

ashley17:08:37

hmm okay, let me give it another try

ashley17:08:25

I think i got it!

ashley17:08:33

It compiled a good file that looks correct

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

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

ashley17:08:48

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

ashley18:08:10

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

ashley18: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.

mouhieddinesabir19: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"]?

mouhieddinesabir20: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 @! 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! ๐Ÿ‘

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.

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

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

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

seancorfield20:08:24

^ @mouhieddinesabir

iagwanderson21:08:46

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

iagwanderson21:08:03

could not find a way to perform that easily =/

iagwanderson21:08:36

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

iagwanderson21:08:28

this is a very nice and useful namespace ๐Ÿ™‚

henri.schmidt21:08:50

yes was gonna say use a pre/postwalk!

schmee21:08:18

that walk function doesnโ€™t work for nested maps though

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

henri.schmidt21:08:24

This works on nested forms with clojure walk

iagwanderson21:08:07

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

iagwanderson21:08:45

thanks @henri.schmidt and @schmee

iagwanderson22:08:21

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

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

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

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

valbaca22: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?

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

valbaca22:08:47

Thank you again ๐Ÿ™‚