Fork me on GitHub
#beginners
<
2018-04-11
>
noisesmith01:04:32

@lgesssler I've heard directly from the person that implemented the foo.core convention in leiningen that it was a way to avoid single segment namespaces with gen-class in them, if you use lein new my.domain/foo you will get my.domain.foo instead of foo.core

๐Ÿ‘ 4
noisesmith01:04:38

(my.domain/foo makes a directory "foo", my.domain.foo makes a directory "my.domain.foo" but the contents appear identical)

brunobraga02:04:08

do any of you guys use clojure.test? if so, is it possible to run all tests except for one (which will be my integration test)? I am trying to just move it to a different folder, but everytime I run lein test it will run every test inside /teste folder.

seancorfield02:04:03

@brnbraga95 Sounds like you could use test selectors for that...

seancorfield02:04:12

lein test help should explain that.

seancorfield02:04:46

You can mark that single test with metadata such as ^:ignore and then define

:test-selectors {:default (complement :ignore)}
in your project.clj

seancorfield02:04:21

Or if you could could just tell lein test which namespaces you want to test (I don't know how many test namespaces you have).

brunobraga02:04:50

my test folder is:

test:
    unity:
       files
    integration:
       files
I tried something like lein test test/unity but had no luck, I can specify each file lein test :only test/unity/test1.clj but that is not very handy

lukesp02:04:39

I am trying to run Cursive in IntelliJ IDEA. I keep getting Could not locate clojure/spec/alpha__init.class or clojure/spec/alpha.clj on classpath.

brunobraga02:04:19

@seancorfield what does (complement :ignore) means? did not quite understand what it is saying

seancorfield02:04:33

@brnbraga95 Specify the namespace not the file path.

brunobraga03:04:24

thanks sean, got it.

seancorfield02:04:06

(complement :ignore) is a predicate that means "does not have :ignore metadata" in this case.

๐Ÿ‘ 4
seancorfield02:04:32

In general (complement foo) is a function that means (not (foo x))

๐Ÿ‘ 4
seancorfield02:04:10

@lukasz.pomorski01 Hard to say based on so little information -- try the #cursive channel as @cfleming is usually very responsive there.

Kari Marttila08:04:08

When I start lein figwheel and the REPL starts, and I interact with the REPL the default font color for my input is really difficult to see (light gray - REPL output is black and ok). Is there some way to change the terminal font colors for Figwheel? Or is this something I have to change in my Linux workstation?

agigao08:04:10

@kari.marttila Iโ€™m a bit confused, can you post a screenshot?

Kari Marttila09:04:43

The font for namespace is light gray (hardly visible). My workstation is Ubuntu14. The terminal is Terminator.

Kari Marttila09:04:52

I made a workaround - I made a remote REPL connection using Cursive - it is more convenient to use Cursive IDE anyway so this is not such a big issue.

Kari Marttila09:04:33

Damn, this is so much fun to learn how to create a SPA using ClojureScript. ๐Ÿ™‚

danm09:04:10

Heh. I wonder if it accepts changes to the base font colour, but all the differently-coloured bits are set elsewhere (or hard set) and everyone else uses terminals with a black background

danm09:04:36

That's the first time I've seen a developer's terminal that's dark text on a light background

agigao11:04:58

@kari.marttila well, I donโ€™t seem have syntax highlighting in figwheel shell. Apologies, I have no idea how to address your issue.

deg12:04:07

Is there any way to apply the namespaced map shorthand syntax to nested keys? That is, is there a briefer way to say #::my-ns{:key1 #::my-ns{:key2 42}}?

deg12:04:08

Ok, thanks.

Kari Marttila12:04:26

@chokheli and @carr0t: Ok. No problem. I'll investigate my Ubuntu / Terminator configuration. And using remote REPL in IntelliJ IDEA / Cursive is anyway more enjoyable since I have all my favorite hot keys there.

Nikos13:04:13

Hi, total Luminus newbie here. I'm reading the book Web Development with Clojure, and I just created a new Luminus app using lein new luminus guestbook +h2. I'm trying to create new migrations using lein migratus create guestbook but I'm getting the error 'migratus' is not a task. See 'lein help'.. Any ideas?

grierson13:04:28

@nikoszp The Luminus http://www.luminusweb.net/docs#creating_the_database website is more upto date. For the first project.

๐Ÿ’ฏ 4
grierson13:04:53

@nikoszp I had similar issues, Luminus has changed somewhat since that book has been release. You have to check the Luminus website/Github for changes or use the specific versions within the book.

Nikos14:04:33

Thanks! I think I'll stick to the most current version and try to figure things out

grierson14:04:50

lein run migrate

grierson14:04:40

Thats the command used on the website.

grierson14:04:15

Or if your using the latest version it might even be boot dev [run migrate]

Nikos14:04:26

I'm looking now, thanks!

grierson14:04:05

No problem ๐Ÿ™‚.

steveh201814:04:08

How can I do this? ((f a b c) [x y z] => [(a x) (b y) (c z)]. where "a b c" are functions. It would be a nice way of converting a vector of string data to a vector of types (numeric, dates, etc). Thanks!

Alex Miller (Clojure team)14:04:12

map over both functions and data in parallel? (map #(%1 %2) [a b c] [x y z])

steveh201814:04:51

Perfect! I was trying out the csv libs, reading in futures data, left with vectors of string data and was thinking...why don't those libs let you pass in a vector of functions to convert all that data to types because that's the first thing one is most likely to do next?

grierson14:04:35

(map (juxt a b c) [x y z]) I think this might work

Alex Miller (Clojure team)14:04:18

I donโ€™t think thatโ€™s what you want

Alex Miller (Clojure team)14:04:30

then you be applying a b and c all to x y and z

sarna14:04:29

hey, do you ever use keywords as values in maps?

joelsanchez14:04:27

keywords are very useful for "enum-like" values, such as in this map example {:type :combobox}

sarna15:04:41

thanks ๐Ÿ‘

Wilson Velez15:04:56

Hi, I need to transform this map {:1 {:pct 60} :2 {:pct 40}} into this {:1 {:pct 60 :amount 120} :2 {:pct 40 :amount 80}}

Wilson Velez15:04:36

I did it this way (reduce into {} (map (fn [[key pct]] {key {:pct (:pct pct) :amount (utils/round (* 200 (/ (:pct pct) 100)))}}) {:1 {:pct 60} :2 {:pct 40}}))

Wilson Velez15:04:23

I also have a version with merge-with

Wilson Velez15:04:35

(merge-with into mimapa (reduce into {} (map (fn [[key pct]] {key {:amount (utils/round (* 200 (/ (:pct pct) 100)))}}) mimapa)))

Wilson Velez15:04:58

being mimapa (def {:1 {:pct 60} :2 {:pct 40}})

Wilson Velez15:04:54

they work, but are they fine?

joelsanchez15:04:23

hi, they look slightly more complicated than needed, try this one

4
joelsanchez15:04:11

if you want to go slightly further, first define this

joelsanchez15:04:47

hyper-concise : )

Wilson Velez15:04:56

to much for my level

๐Ÿ˜‚ 4
grierson16:04:44

Can you make lein repl require clojure.repl automatically? So I can use doc, apropos, source?

john16:04:03

@grierson if you scroll up, @mfikes was just giving some advice on that, I believe: https://clojurians.slack.com/archives/C053AK3F9/p1523335339000044

mfikes16:04:05

Normally clojure.repl/doc and friends are automatically referred into your user namespace when you do lein repl

justinlee18:04:23

I wonder what the experience would be like if a repl had a mode that auto-referred any unique name across all namespaces.

joelsanchez18:04:38

thanks, that has to be more efficient, since it's just one pass

seancorfield19:04:16

Another option is using the xform arity of into:

(defn map-vals [f m]
  (into {} 
        (map (fn [[k v]] [k (f v)])) 
        m))
that's using the single-arity version of map which returns a transducer. That's also single pass (because of how transducers work)

๐Ÿ‘ 4
frenata20:04:57

I've been using:

(defn- fmap [f m] (into {} (for [[k v] m] [k (f v)])))
which is almost identical to that last version @seancorfield. Not sure about the performance implications, would be interesting to test.

noisesmith20:04:50

@andrew354 to make it more like a real fmap, use (empty m) instead of {} - that way it also works on records, sorted maps, etc.

Alex Miller (Clojure team)20:04:12

empty doesnt work on records

๐Ÿ‘ 4
Alex Miller (Clojure team)20:04:33

generally I would expect reduce or the transducer into forms to perform better than for, which is seq based

frenata20:04:35

it could certainly be more general, but it doesn't really need to be

Alex Miller (Clojure team)20:04:32

there are plenty of map-vals impls out there already in various utility libs too

noisesmith20:04:51

the reason I suggested something more general is that the name fmap implies something very general

Alex Miller (Clojure team)20:04:53

check out libs like Medley, Plumbing, Useful, Tupelo, etc

frenata20:04:24

some basic benchmarking: (into {} (for [[k v] m] [k (f v)])) 46 ยตs (into {} (map (fn [[k v]] [k (f v)])) m) 32 ยตs (reduce-kv (fn [m k v] (assoc m k (f v))) {} m) 28 ยตs where f = inc and m = (into {} (map (fn [x] {x x})) (range 100))

Alex Miller (Clojure team)20:04:19

the performance aspects split into consumption of the inputs and production of the output. for is seq-based which in a case like this Iโ€™d expect to produce more objects and thus be slower.

frenata20:04:24

of course it probably doesn't matter unless it's a hotspot, but it was a fun excuse to use criterium

noisesmith20:04:29

also there's two ways to use into with map, the one using the map transducer will be faster

noisesmith20:04:56

it could even be faster than the reduce-kv with assoc

frenata20:04:58

above was the transducer way

noisesmith20:04:13

it was ambiguous with the way you used the ...

frenata20:04:27

sorry. in all cases I used the implementations from above

Alex Miller (Clojure team)20:04:32

there are also issues on the collection side about whether youโ€™re using transients and also how the entries are created

Alex Miller (Clojure team)20:04:35

there is some optimized code around creating maps from vectors and while itโ€™s not obvious, collecting into a transient vector, then creating a map in one step might actually be faster, esp in small common cases (little harder to bench)

Logan Powell21:04:39

Hi everyone! I'm back with another question... I feel like I just hacked together a solution to get the tests to pass for an exercise http://exercism.io/submissions/826a32bc19bc4439ab7a91258ced2a61#L43 Is there a way to bubble/throw up a value instead of an exception? Right now I'm just putting values in that wouldn't ultimately allow for a passing value... I saw this solution from SO, but it didn't work for me: https://stackoverflow.com/questions/32416048/how-to-return-a-value-on-clojure-try-catch

Logan Powell21:04:28

Also, please let me know if I should put code directly in Slack or if the community prefers links to bins or if I should post the question on SO

seancorfield21:04:51

Links are better. Less usage of our very limited space on the free plan.

๐Ÿ‘ 4
noisesmith21:04:58

@loganpowell: a small thing - you don't need to nest let like that

noisesmith21:04:18

let is already able to see previous bindings at each step

Logan Powell21:04:20

The lets can be be inline?

seancorfield21:04:32

You have a cascade of three lets that could all just be one.

Logan Powell21:04:54

thank you ๐Ÿ™‚

seancorfield21:04:30

You could also use destructuring to avoid calling str-2-seq twice:

(let [[digits checkr] (str-2-seq isbn) ...

seancorfield21:04:35

Also (if condition true false) is the same as just condition.

noisesmith22:04:28

or (boolean condition) if someone really needs true or false (no code in clojure itself will care)

seancorfield22:04:02

(that condition yields a true boolean in this case -- and on two boolean operations)

noisesmith22:04:18

oh, yeah, in that case you don't need boolean

Logan Powell22:04:12

are you guys still talking to me?

Logan Powell22:04:04

haha, sorry, which part/line are you referring to?

noisesmith22:04:55

exactly - the condition is already true or false so the if is rendundant

Logan Powell22:04:36

so just the (and... would suffice?

Logan Powell22:04:05

cool! I would never have guessed that and definitely would be confused - if you hadn't just told me - if I saw that in someone elses code ๐Ÿ˜„

seancorfield22:04:28

The Programming Languages course that Univ. Washington teaches (on Coursera, as well as on site) has that as one of their early lessons (in Standard ML but it applies to any expression-based language): if a true false == a

Logan Powell22:04:55

thank you so much. This is one of those many things that I wouldn't even know to ask for help for

seancorfield22:04:56

line 37 in your code seems redundant -- was it left over from when you were developing/testing? The chars on its own in the body of the let with the if following it?

seancorfield22:04:43

let evaluates each expression in the body but returns only the value of the last expression (so it throws away the other values)

Logan Powell22:04:30

ah, yeah, that is not intentional. it's left over from when I was putting it together.

Logan Powell22:04:27

I'm surprised it still worked with that in there

seancorfield22:04:38

'k... range has a step argument so you can replace (reverse (range 2 11)) with (range 10 1 -1) if you want

seancorfield22:04:50

Sure, it evaluates chars and then throws away its value.

seancorfield22:04:10

(let [a 42] 1 2 3 4 5 a) => 42

seancorfield22:04:36

first-9 can be simplified quite a bit: you don't need to make the sequence of pair and then apply * to each, you could just map * over those two sequences to start with.

seancorfield22:04:23

for example (map * (range 10 1 -1) [8 5 6 2 3 4])

seancorfield22:04:09

In your case (map * (range 10 1 -1) (map #(Character/digit % 10) seq))

Logan Powell22:04:03

so map can sort of zip two lists together and apply an operator on the pairs?

Logan Powell22:04:26

wow. that's cool

seancorfield22:04:33

map can take any number of sequences and applies the function across all of them.

Logan Powell22:04:04

what happens if the input sequences are different lengths?

seancorfield22:04:44

(map + [1 2 3 4 5] (range 100 110) (repeat 6)) => (107 109 111 113 115) -- it stops after the shortest sequence

seancorfield22:04:11

In the above, (repeat 6) is an infinite sequence.

Logan Powell22:04:29

very good to know. Man, you're saving me days of learning right now

seancorfield22:04:38

That's what we're here for ๐Ÿ™‚

seancorfield22:04:07

With this exercise, is there anything specified about what should happen if the inputs are not valid?

seancorfield22:04:26

For example, first-9 could throw an exception if it is passed invalid data?

Logan Powell22:04:45

That's actually the original question I posted above, I'd like to get the whole thing just to evaluate to false if any of the sub-assemblies don't return valid values

Logan Powell22:04:15

instead, I've just *hacked* in some values that would never work (hopefully)

seancorfield22:04:30

(try (checking-code ...) (catch Throwable _ false))

noisesmith22:04:56

@loganpowell: one way that can look is (boolean (some->> input (check-1) (check-2) ... (check-n))) where each check function returns either a map of bindings (including ones created by previous steps), or nil (to indicate some condition wasn't met and it failed)

Logan Powell22:04:57

Sweet! You guys are the best

Logan Powell22:04:47

@noisesmith is that using function composition (`->>`)?

seancorfield22:04:54

But you could write

(defn first-9 [digits] 
  {:pre [(= 9 (count digits)) (every? #(Character/isDigit %) digits)]} 
  (reduce + (map * (range 10 1 -1) (map #(Character/digit % 10) digits))))
for example, which would throw an AssertionError if the input (`digits`) wasn't ten characters that represented digits.

Logan Powell22:04:23

so, that would avail false ultimately?

noisesmith22:04:27

@loganpowell: ->> is not function composition (though the end result is similar) - it's a form rewrite

Logan Powell22:04:44

oh boy, I'm in over my head ๐Ÿ˜„

noisesmith22:04:45

some->> is like ->> except it stops if any step returns nil and doesn't run any further steps

noisesmith22:04:50

fair enough!

Logan Powell22:04:21

let me refactor with all these goodies.

noisesmith22:04:25

@seancorfield: one gotcha there is that catch Exception will not catch a precondition

seancorfield22:04:50

cough Throwable cough

Logan Powell22:04:04

@noisesmith is there a term for this (boolean (some->> input (check-1) (check-2) ... (check-n)))

Logan Powell22:04:25

like the convention

Logan Powell22:04:51

does it return 'false`?

noisesmith22:04:53

some->> is a form rewrite, it doesn't have another name that I know of, and boolean turns nil into false

Logan Powell22:04:44

groovy ๐Ÿ™‚

seancorfield22:04:55

(You'd only want the try/`catch` in your top-level isbn? function tho')

Logan Powell22:04:58

ok, thank you guys again!!! I'll be back

seancorfield22:04:05

I just did the above as an example.

Logan Powell22:04:35

ah, cool, I tried that in the sub assemblies and it didn't work. I'll try it at the top!

camachom23:04:07

Anyone using secretary? Is there any way of making it match multiple routes for a single URL?

fmn23:04:42

Hi, how do you spec a vector whose first 3 item is fixed string and can accept a flat sequence of keywords

fmn23:04:17

This pass: ["a" "b" "c"] , ["d" "e" "f" :foo :bar :baz ....]

fmn23:04:46

This shall not pass: ["d" "e" "f" 1 2 3]

fmn23:04:39

I was using s/tuple and s/* and it doesn't work since it expects another collection

justinlee23:04:51

@mcama200 what would that even mean? the point of a router is to route to one place

camachom00:04:41

i think its common with react-router. From their docs " When a <Route> matches it will render its content and when it does not match, it will render null. " Meaning, it attempts to keep matching unless you specify otherwise. It's useful if you want to render a component or do a specific action for a set of routes

justinlee01:04:45

Oh yea no you canโ€™t do that react router 4 thing with secretary