Fork me on GitHub
#beginners
<
2019-02-16
>
Thiago Miranda00:02:11

Hello guys. I am very new in Clojure yet and am now reading Clojure for The Brave and True. I am thinking to read the entirely book first and them start coding for real. Do you think this is a good aproach? How was your process of learning Clojure? I would appreciate some help to speed up my study. I came from Java and have already some contact with functional programming in Javascript.

dpsutton01:02:57

I would work as you go. I find that typing and thinking at the repl helps cement the concepts

Disco Dave01:02:37

Hello, can anyone recommend me some good books for learning clojure? As well as an additional book for learning web development with clojure?

superancetre01:02:59

I am currently reading the Joy of Clojure and it's good!

superancetre01:02:32

@db0349It's a bit dated but most everything is still true, and the second edition was made in 2016 I believe

superancetre01:02:58

But it goes fast, so maybe not a book for total beginner

Disco Dave01:02:06

Okay thank you! Does anyone have any recommendations for a clojure book for web development as well?

practicalli-johnny12:02:06

I have been updating my workshop for server-side web apps, still some work in progress http://practicalli.github.io/clojure-webapps/

Disco Dave01:02:19

And that's fine I've done clojure in the past, and I just need to be refreshed

superancetre01:02:00

maybe someone else can comment on it

Disco Dave01:02:01

Okay thank you

Disco Dave01:02:29

The second edition of Joy Of Clojure is from 2014, but from my understanding clojure hasnt changed a whole lot since then, right?

john01:02:02

pretty much any book ever written about Clojure is still valid. I'm not aware of any glaring deprecations

john01:02:02

new features have been layered on but not much has broke with the past

seancorfield02:02:43

@db0349 The main thing to watch out for in older books is library versions. In particular, the older "monolithic Contrib" (1.2) isn't compatible with newer versions of Clojure, and several of the library names changed. But as long as your book is Clojure 1.3 or later, you're mostly alright /cc @john

superancetre03:02:48

@seancorfield thanks sean, nice to know!

gekkostate09:02:26

Hi everyone! Quick question about using a library created in clojure in a Java project. What I did - I created a library in Clojure and I exported it using lein uberjar. - I took the (non-standalone) .jar and added it to my class path in my Java Project. How can I access the functions from that library in my Java project? What would be the import? Something like import project-name.core? Thanks a bunch!

Alex Miller (Clojure team)09:02:47

-'s in clojure namespaces become _'s

Alex Miller (Clojure team)09:02:05

but whether there is a class to import depends on whether you did aot, gen-class, etc

gekkostate09:02:57

I used aot and gen-class. The gen-class :name is com.myname. So, I can import com.myname but the only function I can access is main.

Alex Miller (Clojure team)10:02:02

all of the functions that use the prefix (by default - in the gen-class'ed namespace) should be available

gekkostate10:02:17

hmm, ok. So if I created another function in my .core which was -somethingElse then that will also be accessible? And since it’s a function, can I do a static import of it?

Alex Miller (Clojure team)10:02:44

yes, it will be accessible and yes I think you should be able to do a static import on it

Alex Miller (Clojure team)10:02:58

it's just a normal java static method on the class

gekkostate10:02:51

Awesome! Gonna give it a shot. Thank you!

Alex Miller (Clojure team)09:02:36

you can also use the java API for invoking Clojure (http://clojure.github.io/clojure/javadoc/)

tjh.xbow11:02:33

Can clojure immutable data structure be used in java like java native data structure? I mean not by the java API for invoking clojure?

Alex Miller (Clojure team)14:02:33

Yes, but they only implement the read APIs

Jan K11:02:17

@tjh.xbow Technically yes, they implement the appropriate java interfaces (vector implements List etc.), but they might not be the most convenient option. https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentVector.java

vlad_poh13:02:31

Howdy Y'all! I'm building a simple compojure + reagent app and I want to use the same compojure service but have it talk to multiple databases. Where should i store the configuration?

Dmytro Bunin13:02:52

why not in your config.edn file?

👍 5
vlad_poh14:02:26

So the service will need to know of the databases before hand? How i reload the config when I add a new db? Is this good practice?

Disco Dave14:02:21

How do people usually abstract out effects in Clojure? Similar to how Haskell would use type classes or object oriented code would use interfaces

eggsyntax17:02:30

- Partly just the discipline of trying to keep most functions pure and segregate side effects into a few places. - Protocols are like OO interfaces. - Or there are a handful of libs (eg re-frame in cljs) that go further, using data to describe desired effects and having a single centralized resource to actually act on them.

futuro15:02:56

Multimethods?

cvetan15:02:01

Hello guys.

cvetan15:02:19

I am startin to learn clojure as a part of my master studies course.

cvetan15:02:36

I've started with book Clojure for the brave and true

cvetan15:02:04

I've created application with leiningen, and I was wondering why this code thorws exception, but prints value before it.

cvetan15:02:15

(ns clojure101.core
  (:gen-class))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  ((def greting "Hello there")
   (println greting)))

cvetan15:02:23

and here is the output.

cvetan15:02:40

Hello there
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn, compiling:(/tmp/form-init7051855349601256406.clj:1:73)
	at clojure.lang.Compiler.load(Compiler.java:7526)
	at clojure.lang.Compiler.loadFile(Compiler.java:7452)
	at clojure.main$load_script.invokeStatic(main.clj:278)
	at clojure.main$init_opt.invokeStatic(main.clj:280)
	at clojure.main$init_opt.invoke(main.clj:280)
	at clojure.main$initialize.invokeStatic(main.clj:311)
	at clojure.main$null_opt.invokeStatic(main.clj:345)
	at clojure.main$null_opt.invoke(main.clj:342)
	at clojure.main$main.invokeStatic(main.clj:424)
	at clojure.main$main.doInvoke(main.clj:387)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:702)
	at clojure.main.main(main.java:37)
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn
	at clojure.lang.Var.fn(Var.java:365)
	at clojure.lang.Var.invoke(Var.java:381)
	at clojure101.core$_main.invokeStatic(core.clj:7)
	at clojure101.core$_main.doInvoke(core.clj:4)
	at clojure.lang.RestFn.invoke(RestFn.java:397)
	at clojure.lang.Var.invoke(Var.java:377)
	at user$eval149.invokeStatic(form-init7051855349601256406.clj:1)
	at user$eval149.invoke(form-init7051855349601256406.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:7062)
	at clojure.lang.Compiler.eval(Compiler.java:7052)
	at clojure.lang.Compiler.load(Compiler.java:7514)
	... 12 more

cvetan15:02:11

as you can see value is displayed but after that exception is thrown.

cvetan15:02:33

I probably don't understand how functions/main work, so if you could point me... 😄

Alex Miller (Clojure team)15:02:47

def should only be used at the top level (like where you have ns and defn)

Alex Miller (Clojure team)15:02:16

functions have an implicit body and can take multiple expressions - you have them grouped in a set of parentheses

Alex Miller (Clojure team)15:02:30

parentheses mean function invocation

cvetan15:02:42

so how would I save value that needs to be printed but takes value based on some logic?

Alex Miller (Clojure team)15:02:45

so the def expression is getting evaluated, then the println, then you are trying to invoke the result of the def (a var) with the result of the println (nil). vars are invokable actually

Alex Miller (Clojure team)15:02:33

(defn -main
  [& args]
  (let [greting "Hello there"]
    (println greting)))

Alex Miller (Clojure team)15:02:53

let creates locally scoped bindings

Alex Miller (Clojure team)15:02:56

(defn -main
  [& args]
  (let [a 1
        b (+ a 1)]
    (println a b)))

Alex Miller (Clojure team)15:02:08

let bindings can build on each other

cvetan15:02:06

is there some good IDE that would give me syntax errors and similar for clojure?

cvetan15:02:24

right now I am writing code in Sublime Text, and manually running lein run.

Alex Miller (Clojure team)15:02:57

the most popular are Emacs with CIDER (https://github.com/clojure-emacs/cider) or Intellij with Cursive (https://cursive-ide.com/)

Alex Miller (Clojure team)15:02:03

Some others to consider are VS Code with Calva, or Atom with a variety of plugins (I'm not up on the latest there)

Chase15:02:18

I use emacs but I think every editor is going to have some kind of basic setup to integrate with the clojure repl. That's the key, you want to start using the repl. So google sublime text clojure repl setup or something similar. Or if you want something more like Sublime Text but a little more popular for Clojure development look into Atom w/ Chlorine or Proto repl (I think it's called) or VS Code and Calva.

Chase15:02:33

yup, what Alex said. haha

cvetan16:02:55

can you show me example of using def?

cvetan16:02:16

I've tried like this, still get Exception

cvetan16:02:20

(ns clojure101.core
  (:gen-class))

(def random-number (rand-int 11))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  ((if (< random-number 5)
    (println (str random-number "Number is smaller than 5!"))
    (println (str random-number "Number is bigger than 5!")))))

superancetre16:02:50

It's because you have two open parentheses before the If

superancetre16:02:09

(defn -main

 "I don't do a whole lot ... yet."

 [& args]

 (if (< random-number 5)

   (println (str random-number "Number is smaller than 5!"))

   (println (str random-number "Number is bigger than 5!"))))

superancetre16:02:17

oops formating 😕

superancetre16:02:30

howd do you format code here?

cvetan16:02:03

I am not sure I understand you.

superancetre16:02:40

I would like to have the snippet of code I wrote to be formatted as code, the same as in your message

cvetan16:02:02

well you use `

cvetan16:02:08

and ` after the code

lilactown16:02:18

use triple backtics

cvetan16:02:19

that is for multiline code

cvetan16:02:28

for inline you use single

superancetre16:02:40

@cvetan.simsic To get back to your problem, when you define a function like,

(defn example-fn 
  [arg1]
  (println arg1))
You only need one set of parenthese around what's inside the function definition If you write
((some-fn arg1 arg2))
it means that some-fn is a function returning a function

superancetre17:02:28

like

(defn closure
  [n]
  (fn []
     (+ n 1)))

yngve18:02:30

👋 hello, I'm new here

yngve18:02:40

I'm setting up codox, for generating documentation. In my project.clj I've configured it with :codox {:metadata {:doc/format :markdown}}

yngve18:02:05

and ive tried writing by docstrings both as just regular docstrings and as the doc meta ` (defn foo [x] " Returns x" {x}) (defn foo [x] {:doc "Returns x"} {x}) ` But the docstrings and arguments arent added in my documentation. My namespaces are enumerated just fine.

dpsutton18:02:33

Check the form for defn. I believe the docstring goes before the arg vector to disambigate the docstring from a value in the body of the function

👍 5
yngve18:02:01

oh, right

yngve18:02:59

you are absolutely right, solved

yngve18:02:01

thank you!

41ph4_Ph4un19:02:11

Hi! setting up Leiningen with shadow-cljs and having a bit of a headache

41ph4_Ph4un19:02:32

I can call shadow-cljs nicely with npm but it seems that invoking calls via lein fail, etc: lein run -m shadow.cljs.devtools.cli help produces just "Unknown action."

thheller19:02:05

@theamazingekko did you try anything else but help? that action only happens to be implemented on the JS side 😉

thheller19:02:21

compile etc should work fine

41ph4_Ph4un19:02:00

yeah it works xD

thheller19:02:26

you may not want to use lein to run things as that does not work with the server mode

thheller19:02:46

you can just configure :lein in shadow-cljs.edn and it will use lein to run things internally https://shadow-cljs.github.io/docs/UsersGuide.html#Leiningen

41ph4_Ph4un19:02:09

ah yes already changed that, if you mean adding that true -value? 🙂

41ph4_Ph4un19:02:15

hmm.. I know the user manual is still work in progress but I think the help -command should be omitted from the examples. I know it was stupid of me not to try other commands but it kinda tripped me as it was the first step in testing calling commands from lein 😄

thheller19:02:21

indeed 🙂 I'll fix that

41ph4_Ph4un19:02:05

no problem! thanks a bunch for the help though! Really looking forward to getting to know this tool 🙂

thheller19:02:50

if you have questions come on by #shadow-cljs. I don't always notice questions here.

41ph4_Ph4un19:02:33

noted! thanks 🙂

gabriele23:02:44

how idiomatic is doing something like this

(def ^:dynamic add-acc)

(defn pipeline []
  (into [] 
    (map (fn [x] 
      (add-acc x)
      (inc x)) (range 10))))

(let [state (volatile! [])]
  (binding [add-acc (fn [x] (vswap! state conj (* 2 x)))]
    (pipeline)
    @state))
is there a better way to accumulate a value inside a transducers pipeline?

lilactown23:02:15

using an atom/volatile seems fine: https://clojure.org/reference/transducers#_transducers_with_reduction_state your example doesn’t seem to be really using transducers, though, just a regular map over a sequence. one thing to note is that a transducer might be lazy, in which case using binding probably is a bad idea

gabriele23:02:58

(into [] xform coll) is using a transducer, it is just an example tho

lilactown23:02:16

ah misread the parens 😅

lilactown23:02:50

I think the idiom is to use a higher-order function to create the stateful transducer

gabriele23:02:08

let me change the example a little

gdubs23:02:49

Hello! Trying to get Emacs+Cider going. I can open the repl buffer, and go into 'insert mode' and type stuff, but how do I get it to evaluate? 😛

gdubs23:02:25

ok, hitting return worked... but didn't before. sorry for the lame question.

👍 20
eggsyntax18:02:43

All parens have to be closed for it to evaluate on return — otherwise it assumes you want to continue onto another line. My guess is that’s what you were tripping over.

practicalli-johnny12:02:48

You can evaluate code in the Clojure buffer too, in Vim normal state using SPC e f and other commands under SPC e

gabriele23:02:37

(def ^:dynamic add-acc)

(defn pipeline []
  (into [] 
    (comp 
      (map (fn [x] (add-acc x)(inc x)))
      (map (fn [x] (add-acc 10) (dec x))))
    (range 10)))

(let [state (volatile! [])]
  (binding [add-acc (fn [x] (vswap! state conj (* 2 x)))]
    (pipeline)
    @state))
i need to be able to accumulate the value in any transducer inside the "pipeline"

didibus23:02:35

That looks like some weirdly bad approach to wtv you are doing.

gabriele23:02:54

so i can't use a stateful transducer

lilactown23:02:51

sounds like what you need is reduce, not a transducer, unless I’m misunderstanding you