Fork me on GitHub
#beginners
<
2018-08-24
>
jlmr08:08:04

Hi, what is the recommend way of setting things like print-length automatically at repl startup? I'm using deps.edn.

tbsvttr11:08:47

Hi. I just discovered Clojure (again). This time I really want to give it a try! I am comming from the front end and mostly work with TypeScript and Vue.js at the moment.

tbsvttr11:08:01

Is there a tutorial for ClojureScript you could recommend?

tbsvttr11:08:04

Which editor or IDE is good for beginners? At the moment I am am doing everything I can with VSCode.

tbsvttr11:08:04

Should I use Leiningen or Boot as a beginner?

tbsvttr11:08:51

And should I go for Om or Reagent at the beginning?

tbsvttr11:08:56

Does it make sense to learn Clojure without having any knowledge of Java to speak of? Last time I got quite some tracebacks talking Javarish when someting did not work correctly.

ben08:08:07

As an also beginner, I’ve found lein and vs code good for me. My coworkers recommend spacemacs as an editor, but that seems like overkill for me rn.

👍 1
manutter5111:08:18

A frequently-recommended tutorial would be Clojure for the Brave and True, available online (https://www.braveclojure.com/) and in book form. There’s also a #braveandtrue channel on this slack specifically for people working through that tutorial

👍 4
manutter5111:08:50

There are several good editors: I use IntelliJ with the Cursive plugin, others are using Atom with the appropriate plugins, and I think there’s a Clojure plugin for VSCode? Maybe, not sure on that one.

👍 1
manutter5111:08:58

For front end work I recommend re-frame, which is built on top of Reagent. https://github.com/Day8/re-frame. Re-frame has a fairly thorough README, but don’t let that fool you, the real docs are in the /docs folder. Also be sure to read the todomvc example in the /examples folder--there’s a bunch of extra documentation in the comments that’s worth having.

👍 1
manutter5111:08:25

I use Leiningen for pretty much everything, never made the jump to Boot. I have heard some say that Boot is better for CLJS stuff, but I’ve never been motivated enough to try it out. One thing in Lein’s favor is that there’s a bunch of people who know it and can help out if you have issues.

👍 1
manutter5111:08:01

If you’re mostly developing front end stuff, the Java side shouldn’t be too much of an issue (I have a site in production now that is CLJS exclusively, no Java anywhere). But if you do run into problems feel free to ask and to post stack dumps in snippets and someone will likely have a look and see if they can help out.

👍 1
henrik11:08:15

I personally use Atom + Proto-REPL + Parinfer.

henrik11:08:25

I highly recommend trying out #parinfer if you haven’t already. It juggles brackets and indent levels for you using clever mathematics. The #parinfer devs are bumping into problems of inflexibility with VSCode that’s slowing down progress on the latest version of parinfer for VSCode (though an older version is available). Were it not for that, I would give VSCode a serious go.

pez12:08:13

Thanks for the Calva shout-out! Anyone who does everything in VSCode should try it out. 😍 In waiting for Parinfer, the combo of Calva Formatter and Calva Paredit works pretty well (in my, biased, opinion).

💯 1
👍 1
Michael Stokley16:08:38

with regard to the ^:private metadata tag: it looks like this hides functions from unit tests. how do folks conventionally balance the need to unit test and the need to hide implementation details?

dpsutton17:08:56

#'var-name will let you grab the var. you can test it even though it is private. I think there are some languages that let the runtime know that the test code is privileged in some manner and you don't need to do this.

wekempf17:08:18

@michael740 Conventional wisdom for other languages is that you shouldn't be testing private implementation details in the first place, and I don't see why it would be different in Clojure.

👍 1
wekempf17:08:36

You'll test that code indirectly by testing the public code that calls it.

dpsutton17:08:00

that doesn't seem very wise to me. you should absolutely test private things that aren't shown to outsiders

dpsutton17:08:22

re: conventional wisdow

dpsutton17:08:55

if a public interface relies on an implementation of shortest path through a graph you can and should write some tests around your graph traversal

wekempf17:08:57

It is tested... indirectly. What purpose is served testing it directly?

hiredman17:08:22

compromise: never use ^:private

👍 2
dpsutton17:08:31

if there's lots of private functionality to get the public api to work, why leave it untested. and then if there is a bug in your graph traversal your unit test for the public api would just say some nonsense error and not help you. why wouldn't you want confidence in the edge cases of private implementations

dpsutton17:08:09

further, the input to the api to hit edge cases in private functions might be quite annoying to put in the test but the input to the private functions could be trivial to probe the edge case

wekempf17:08:41

If those edge cases are never hit with the public code, why do you care? Test behavior, not implementation.

Michael Stokley17:08:38

> if there is a bug in your graph traversal your unit test for the public api would just say some nonsense error This is the situation I find myself in now. I couldn't debug my main function, so that seemed like a sign I should decompose it

hiredman17:08:57

I was not kidding about not using ^:private

Michael Stokley17:08:32

do you think having everything exposed publically could confuse clients of your package?

hiredman17:08:32

why would it?

Michael Stokley17:08:06

because there may be some helper functions there that don't make sense / aren't useful outside of the context of your implementation

hiredman17:08:35

why would that confuse clients?

Michael Stokley17:08:45

maybe i'm decomposing too much

wekempf17:08:46

Put them in a separate namespace?

wekempf17:08:34

@pez Anything I should know to get ANSI colors in VSCode's terminal when running the REPL (or lein, for that matter)?

pez18:08:10

You mean syntax highlighting of clojure code? If so, no, that is not anything that Calva can help with atm. Do you have it working in done other terminal?

wekempf18:08:41

Lots of clojure tools output ANSI escape codes to colorize the output. For instance "lein cljsbuild once min" compiles your code and the last line it prints out is a "Successfully compiled" message in green. Or, it would be if the console supported ANSI escape codes.

wekempf18:08:05

I know Calva doesn't do anything with the console, but I figured if you work in VSCode you might know the answer here.

wekempf18:08:46

VSCode is supposed to handle ANSI escape codes according to some google searches, but they show up as funky characters in my output by default.

wekempf18:08:47

In Win10 the console also supports them, but I get the same result. But, to use them there a special mode needs to be entered by the application, and I guess lein doesn't bother with this.

wekempf18:08:57

The lein README suggests using ansicon, which is a bummer since the console should support it anyway, but I installed it.

wekempf18:08:03

Works fine in my PowerShell console, but it's messed up in VSCode. Does produce colors, but afterwards the colors are all out of whack (I get a pink background until I start to type... really ugly).

wekempf18:08:10

That "boolean?" warning is a different matter, but this shows how ansicon and VSCode aren't playing nice for me.

Mario C.21:08:14

I am getting an error No reader function for tag object when I call this function (read-string my-str). Does anyone know why I am getting this error?

hiredman21:08:36

it means you have no reader function for some tag literal in my-str

Mario C.21:08:07

my-str looks something like #something.types.Model{..stuf...}

hiredman21:08:03

that might be a record literal vs a tag literal, I forget exactly how the reader discriminates between the two

hiredman21:08:33

but the reader might first attempt the record literal, then tag literal, so the error you get for a missing record literal is that tag literal error

quadron21:08:35

A philosophical question: to pass atoms and channels down my functions? or to lift values out into monads? or have a stream topology, where information flows and triggers callbacks?

hiredman21:08:48

nah, it might be a tag literal in ..stuff..

Mario C.21:08:13

Thanks I think I know what to do now

moo21:08:02

Hi guys, any idea why this doesn’t work:

(def big-number-stream "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450")

(def number-list 
  (map #(Integer/parseInt %) 
       (map str big-number-stream)))

(map * (partition 4 number-list))
;; --> ClassCastException Cannot cast clojure.lang.LazySeq to java.lang.Number  java.lang.Class.cast (Class.java:3578)

moo21:08:30

number list works and partitioning it works

quadron21:08:38

@moo you gotta realize it

moo21:08:48

soooo lazy

moo21:08:12

realize?

noisesmith21:08:57

lazy data is realized by accessing it - this could be as simple as printing or counting it

quadron21:08:24

@moo doall

hiredman21:08:42

you are mapping * over seqs of numbers

noisesmith21:08:46

@veix.q5 that error is not being caused by laziness

hiredman21:08:52

not a seq of numbers

hiredman21:08:06

* doesn't take a seq of numbers, it takes numbers

quadron21:08:44

(map (partial reduce *) (partition 4 number-list))

moo21:08:24

I see I have a “what collection are you talking about” problem…

hiredman21:08:28

maybe use apply

moo21:08:58

because (take 1 number-list) gives ((7 3 1 6))

noisesmith21:08:13

that's what I'd expect, yes

moo21:08:25

and (reduce * (take 1 number-list)) returns (7 3 1 6)

noisesmith21:08:38

that's an accidental non-error

noisesmith21:08:56

(reduce f [x]) returns x for all f and x

moo21:08:03

(map (partial reduce *) (partition 4 number-list)) works btw

moo21:08:12

I just need to understand wft is going on hehe

noisesmith21:08:17

reduce doesn't call f if you supply no initial item and there's only one item in the coll

moo21:08:47

but I don’t get why if that mapping partial reduce works, then why doesn’t take 1 then reduce work

noisesmith21:08:24

because reduce doesn't call your function if you supply no starting value and there's only one item in the coll

noisesmith21:08:39

it steals the first item to make it the initial value

noisesmith21:08:53

f doesn't get called because there's now nothing in your coll

noisesmith21:08:01

so it returns the first item (the initial value)

moo21:08:12

(reduce * (take 2 (partition 4 number-list)))
ClassCastException clojure.lang.LazySeq cannot be cast to java.base/java.lang.Number  clojure.lang.Numbers.multiply (Numbers.java:148)

noisesmith21:08:31

because (* list list) is an error

moo21:08:52

so that’s why have to map the reduce *

quadron21:08:58

(map (partial apply *) (partition 4 number-list))

moo21:08:35

@veix.q5 that works too

moo21:08:49

somehow that’s less funny feeling

noisesmith21:08:14

* is one of those cases where partial and reduce do the same thing in the two argument case

quadron21:08:46

simply mapping over a collection of collections does not work because does not work with collections

quadron21:08:50

(map * [1 2 3])

quadron21:08:56

does not work

noisesmith21:08:02

that's wrong

quadron21:08:02

but (apply * [1 2 3])

noisesmith21:08:05

map makes it work

moo21:08:08

so mapping * doesn’t work because you can’t multiply a list

noisesmith21:08:23

you maybe meant (map * [[1 2 3]])

moo21:08:25

and apply is taking the contents of the lists and supplying them to * as args?

moo21:08:13

I mean my original (map * (take 2 (partition 4 number-list)))

andy.fingerhut21:08:32

(map * [1 2 3]) gives the same result as (list (* 1) (* 2) (* 3)) - although I may be fudging a bit with the list part there

noisesmith21:08:43

I was specifically talking about (map * [1 2 3]) - that returns the lazy-seq (1 2 3)

moo21:08:44

that doesn’t work because ((7 3 1 6) (7 1 7 6)) are two lists

👍 1
andy.fingerhut21:08:51

which is not what you want if your goal was to multiply 1 by 2 by 3

andy.fingerhut21:08:09

(apply * [1 2 3]) gives the same result as (* 1 2 3) or 6

moo21:08:11

okay so is (map #(apply * %) (take 2 (partition 4 number-list))) is the same as (map (partial apply *) (take 2 (partition 4 number-list)))

noisesmith21:08:58

yes, that's how partial works

moo21:08:33

Thanks guys

quadron21:08:52

i stand corrected: (map * [[1 2 3]]) does not work

moo21:08:14

what’s the right idiom if I wanted to simulate a “moving-window” of 4 digits? For example, thinking in non functional (’cause that’s where my brain is at), I would: (partition 4 number-list) (partition 4 (drop 1 number-list)) and so on until drop 3 then if I appended all that together my map apply * would give me the largest product of any 4 consecutive digits

moo21:08:22

or I could use tail recursion and an accumulator that eats another digit to make a 4 digit window

moo21:08:21

I’ll go play with it. Thanks for your help guys

seancorfield21:08:41

@jm.moreau partition takes a step argument so you can do (partition 4 1 number-list)

👍 1
seancorfield21:08:56

boot.user=> (partition 4 1 (range 15))
((0 1 2 3) (1 2 3 4) (2 3 4 5) (3 4 5 6) (4 5 6 7) (5 6 7 8) (6 7 8 9) (7 8 9 10) (8 9 10 11) (9 10 11 12) (10 11 12 13) (11 12 13 14))

_rj_r_21:08:18

what would be the cons to using something like HugSQL vs just writing regular Clojure queries or having some other type of SQL query file?