Fork me on GitHub
#beginners
<
2019-02-16
>
marine.rlivielor00: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

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

julien.rouse01:02:59

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

julien.rouse01:02:32

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

julien.rouse01:02:58

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

db034901:02:06

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

jr0cket12:02:06

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

db034901:02:19

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

julien.rouse01:02:00

maybe someone else can comment on it

db034901:02:01

Okay thank you

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

julien.rouse03: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!

alexmiller09:02:47

-'s in clojure namespaces become _'s

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

alexmiller10:02:02

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

alexmiller10:02:20

so -main becomes main

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?

alexmiller10:02:44

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

alexmiller10:02:58

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

gekkostate10:02:51

Awesome! Gonna give it a shot. Thank you!

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

alexmiller14:02:33

Yes, but they only implement the read APIs

jkr.sw11: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

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

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

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

cvetan.simsic15:02:19

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

cvetan.simsic15:02:36

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

cvetan.simsic15:02:04

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

cvetan.simsic15:02:15

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

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

cvetan.simsic15:02:23

and here is the output.

cvetan.simsic15: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

cvetan.simsic15:02:11

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

cvetan.simsic15:02:33

I probably don't understand how functions/main work, so if you could point me... πŸ˜„

alexmiller15:02:47

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

alexmiller15:02:16

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

alexmiller15:02:30

parentheses mean function invocation

cvetan.simsic15:02:42

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

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

alexmiller15:02:58

use let here, not def

alexmiller15:02:33

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

alexmiller15:02:53

let creates locally scoped bindings

alexmiller15:02:56

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

alexmiller15:02:08

let bindings can build on each other

cvetan.simsic15:02:06

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

cvetan.simsic15:02:24

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

alexmiller15:02:57

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

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

chase-lambert15: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.

chase-lambert15:02:33

yup, what Alex said. haha

cvetan.simsic16:02:55

can you show me example of using def?

cvetan.simsic16:02:16

I've tried like this, still get Exception

cvetan.simsic16: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!")))))

julien.rouse16:02:50

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

julien.rouse16: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!"))))

julien.rouse16:02:17

oops formating πŸ˜•

julien.rouse16:02:30

howd do you format code here?

cvetan.simsic16:02:03

I am not sure I understand you.

julien.rouse16:02:40

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

cvetan.simsic16:02:02

well you use `

cvetan.simsic16:02:08

and ` after the code

lilactown16:02:18

use triple backtics

cvetan.simsic16:02:19

that is for multiline code

cvetan.simsic16:02:28

for inline you use single

julien.rouse16: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

julien.rouse17:02:28

like

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

yngve.molnes18:02:30

πŸ‘‹ hello, I'm new here

yngve.molnes18:02:40

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

yngve.molnes18: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

yngve.molnes18:02:59

you are absolutely right, solved

theamazingekko19:02:11

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

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

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

theamazingekko19:02:09

ah yes already changed that, if you mean adding that true -value? πŸ™‚

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

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

theamazingekko19:02:33

noted! thanks πŸ™‚

gabriele.carrettoni23: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

gabriele.carrettoni23: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

gabriele.carrettoni23:02:08

let me change the example a little

gdwarner23: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? πŸ˜›

gdwarner23:02:25

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

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.

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

gabriele.carrettoni23: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.

gabriele.carrettoni23: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