Fork me on GitHub

so for someone kind of new to programming would learning racket/scheme (using the how to design programs book and then sicp) before diving into Clojure be a smart approach? I was going to check out Common Lisp too and a couple of the really good texts on that language. On a whim, though, I just tried out the little starter app with reagent and figwheel. All with a few command line lein prompts. And tried the live reloading. Wow!


is clojure the better one to start with to create real world web apps and apps in general? is it much harder to learn first? Should I stick with my Racket/Scheme plan or is there similar resources for a beginner to jump right into clojure?


no need to learn those other languages as a prerequisite, just dive right in to Clojure! πŸ™‚


as you become more proficient at clojure, you can adapt sicp and how to design programs to Clojure without too much hassle


this book has a good reputation in the community for beginners:


also, a new version of Programming Clojure was released just last week:


I’ve read the 2:ed edition and I can definitely recommend it for beginners


awesome. i'll check it out. i've heard clojure had a large learning curve. and that it would help to know java for the interop stuff (which isn't a big interest for me, but what do I know, maybe I'm missing out). sounds like it's doable though


fwiw, i know very little Java, and i get by in Clojure just fine πŸ™‚


the error messages and docstrings do expose you to some Java concepts, but it's not too bad imo


same for ClojureScript (though i do know JavaScript quite well, so maybe i just don't see the knowledge required)


Java/JavaScript knowledge is helpful though


ok cool. i'm basically a beginner. i've only explored some beginning tutorials for a few languages, seeing what catches my interest. so no java and not much js but it is what it is!


yeah, i personally would not recommend Clojure as a first language (it's not designed with programming beginners in mind), but different things work for different people πŸ™‚. Clojure is definitely worth giving a shot


Racket/Scheme is also an excellent choice (and they're much more beginner-friendly)


another beginner Clojure book i've seen recommended is Living Clojure, by the way


one other language you might want to look into is Lua (which i've heard is also beginner-friendly)


i think i'll do these first couple racket books and then decide from there. i'm all stoked on these lisp family languages though! seem fun and powerful!


oh, yeah, lisps are wonderful :~)


welcome to programming by the way, it's a lot of fun! (often ;)


@U61HA86AG ClojureBridge does very well teaching Clojure as a first language. Not sure why you think it isn't?


@U04V70XH6 I'm quite sure it's possible to teach a curated subset of Clojure to programming novices - it's a cogently designed, wonderfully simple language, and a lisp to boot. I'm not sure why you'd choose to though; it takes a great deal of effort to make a language and its ecosystem (which in Clojure's case, being two languages in one, also includes the not-so-friendly Java/JavaScript/C# ecosystems) as a whole beginner friendly (and requires design compromises), and that is not where Cognitect's (or the majority of the community's) efforts have been directed, which is understandable, since Clojure is a language for jaded veterans - it's designed to be a violin, not a kazoo. Clojure is designed to be a practical and robust language for professional programming; not to be easy and fun to get started with and use. it's simple, not easy. Beginners need both (or even ease over simplicity; Ruby and JavaScript show beginners don't necessarily need simplicity). Beginners should not have to expend a lot of effort to learn something, it should come naturally, and that's not the level of skill Clojure has been optimised for. Everything from the errors, to the standard library, to additional tools like spec, to the documentation requires active buy-in and competence from the programmer. I don't consider that a bad thing, but nor do I think it's an ideal environment for novices. Since languages exist that are more optimised for the beginner experience, and aren't two languages in one, like Elm, Scheme, Smalltalk, or Lua, and it does not matter too much what your first language is (mine was Python), so long you are able to grasp the fundamentals of programming easily and enjoy doing so, there doesn't seem to be much reason to recommend Clojure as a first language.


whether it has a large learning curve or not depends a lot on you previous experience as well as your expectations


if you’re used to C-style programming and have no previous exposure to functional programming there will be a lot to take in πŸ™‚


if you’re coming from, say, Javascript, which has first-class functions and dynamic typing the gap is smaller


c++11 has lambdas and auto tags πŸ˜„


yeah I’m thinking C99 πŸ˜›


@schmee I would say the hardest background to come to Clojure from is one that has only ever known Java-style OOP πŸ™‚ /cc @noisesmith

Andrew Gracey05:03:46

Hey, I'm trying to get lein installed on windows 10 and having issues with the lein self-install command. It's complaining about the SSL cert but neither of the suggestions work for me.

Andrew Gracey05:03:09

Google isn't helping me and I'm typically a linux user so my powershell is pretty basic


@agracey: I don't know windows, but is set actually part of the syntax for setting an env var?

Andrew Gracey05:03:41

It seems to be ok if I remove the offending -O but then the download still doesn't work


@agracey: supposedly the syntax is $env:MyTestVariable = "My temporary test variable."


so you would use $env:HTTP_CLIENT = "..." I guess?

Andrew Gracey05:03:56

Yeah powershell isn't happy about that either

Andrew Gracey05:03:50

Are there instructions on what the ~/.lein directory shoudl look like at the end? I can download the file and place it myself

Andrew Gracey05:03:13

Or does lein self-install take any additional flags?


$ tree ~/.lein/
β”œβ”€β”€ credentials.clj.gpg
β”œβ”€β”€ profiles.clj
β”œβ”€β”€ repl-history
└── self-installs
    β”œβ”€β”€ leiningen-2.6.1-standalone.jar
    β”œβ”€β”€ leiningen-2.7.1-standalone.jar
    └── leiningen-2.8.1-standalone.jar


the only file you actually need is a single jar under self-installs/ the rest are optional / automatically created

Andrew Gracey05:03:42

hmm, it's trying to download a .zip file... Does it just rename it to .jar? The structure of the zip looks like a jarfile


that has to be it, but I'd have no idea why it would need to do that?

Andrew Gracey05:03:23

Awesome, that worked. running the repl now.

Andrew Gracey05:03:55

On another topic, is there a favorite container base image that people tend to use for clojure projects?

Andrew Gracey05:03:33

Is it worth filing a bug with the issue I ran into?


@agracey Might also be worth taking a look at Boot -- I think it's much more beginner-friendly than Leiningen, to be honest.


hey all, I've having some trouble here. For some reason this expression is always returning the entire "data" object instead of just the count of the "ids" array which is would think it should return


(.get Twitter "followers/ids" params
  (fn [err data]
      (println "count" (count (.-ids data))))
    (count (.-ids data)))))


which expression, the .get?


also we really need to know what Twitter is here to give a meaningful answer


who does that fn return to? who calls it? what gets done with the value the function returns?


(and a minor thing - do inside an fn body is redundant, it already has an implicit do)


Hey all, I am working with a data structure like this:

(def data [{:type :first :items [1 2]} {:type :second :items [1 2]} {:type :third :items [1 3 ]} {:type :first :items [1 5]}])
I want to transform the above into this:
(def data [{:type :first :items [ [1 2] [ 1 5 ] ]} {:type :second :items [1 2]} {:type :third :items [1 3]} }])
So for all maps with the same :type I want to combine their items together I have tried a few things, but I want to confirm that there isn't a util that does exactly this?


there's nothing that does that exactly, but if I was solving that from scratch I'd start with group-by


(group-by :type c) then manage each of the vals individually


Great. That's what I was looking for


thanks @noisesmith, sorry I fell asleep


here's the context around the other snippet I posted


(defn doStuff []
  (println "sending request...")
  (let [twitter twit]
    (def Twitter
      (new twit
           #js {:consumer_key        "CsRZ0L9oBGWhIs2pNp7CFdzU7"
                :consumer_secret     "fC5rr11BWtJGCTxU7prS9WMz4AK6HXgyl2DtVwGdT1zfdfdUcdE"
                :access_token        "3930103636-zJiKnCIljqIGPZJrGKWhUS55BgfrrTHWYQ31ytr5"
                :access_token_secret "2envh7Jz6mmbDD7yeewSGZhsKCZ7TsuLWSOajeWWkFQned"})))
  (def params {})
  (.get Twitter "followers/ids" params
        (fn [err data]
            (println "count" (count (.-ids data))))
            (count (.-ids data)))))

Andrew Gracey16:03:10

You really need to edit this to remove the tokens


"twit" is a js library that I added with (:require [twit :as twit])


you might not want to share your secret key here, but the salient point is which thing is "returning" and who to? I would expect something with an api that looks like that to run your callback, and nothing to use the return value of your callback


I would expect (.get ...) to return nothing useful, or at besta handle you can use to cancel a running http interaction


but the callback function for .get has all the data I want to return


but nothing uses the return value of your callback


it gets called by somebody else, and they ignore the return value


you need to put the value somewhere, or launch something that uses it


or maybe I'm misunderstanding your issue


(defn doStuff []
  (println "sending request...")
  (let [twitter twit]
    (def Twitter
      (new twit
           #js {...})))
  (def params {})
  (.get Twitter "followers/ids" params
        (fn [err data]
            (println "count" (count (.-ids data))))
            (count (.-ids data)))))

(deflambda run-lambda []


run-lambda is an AWS lambda function which I want to return the "data" value from .get


well I actually want it to return just the length of the "ids" property of data


but it's returning the full data object for some reason


@derpocious - my hangup here is that nothing consumes that final count call


and dostuff is either going to return a handle to an async operation, or nothing useful at all


hmm so what would be the right way to just return the count?


you can't because the operation is async


async is contagious - you need to launch another async thing from the callback, or push the data somewhere that something else will see it from in the callback


this is why people use core.async or js/Promise


though to be fair, those things are just as contagious πŸ™‚


right - because they are also async


you have opted in when you go async, your options are all async, some are saner than others


ok I can try to use core.async


so do I then need to wrap the Twitter.get in a channel since it's not a normal js lib not meant to be used in core.async?


in that case you would write to a channel with put! in the callback function, and have a go block that reads from that chan


ok thanks, and put! works for cljs too bc it's asynchronous right?


right - it's the way to asynchronously put a value on a channel


there's also take! which takes a callback and is async, going the other way


I see, and these are also the same and <! and >! ?


not precisely the same, because they also lift into async (or drop back from async) and take a callback - they are like (go (f (<! c))) or (go (>! c v)) / (go (f (>! c v)))


but cheaper because they don't need the go mechanisms


ahh ok thanks πŸ‘


hey all I'm wondering if this is "idiomatic clojure" code.


(def myChan (chan))
(def otherChan (chan))

(defn doStuff []
  (println "sending request...")
  (let [twitter twit]
    (def Twitter
      (new twit
           #js {:consumer_key        "efvrfvrfvrfv"
                :consumer_secret     "rfvrfvrfv"
                :access_token        "3930103636-rfvrfvrfv"
                :access_token_secret "rfvrtbg5tb5t"})))
  (def params {})

  (.get Twitter "followers/ids" params
        (fn [err data]
          (put! myChan (count (.-ids data)))))

  (.get Twitter "friends/ids" params
        (fn [err data]
          (put! otherChan (count (.-ids data))))))

(deflambda run-lambda []
    (let [firstThing (<! myChan)
          secondThing (<! otherChan)]
      {:f firstThing :s secondThing})))


It returns the map { :s 1915 :f 1920 } which is what I wanted, but I was just wondering if this is readable code and the "normal" way to do it.


In particular, I wasn't sure how to get access to things from two different channels at the same time so I just wrapped them in one big "let" block inside of the "go" block. Not sure if that's the best way to do it.


that's exactly how it's normally done


also to be clear, go returns a channel - async is contagious


wait, what do you mean exactly by contagious?


I mean that the hash map on the last line of your code doesn't get returned by that "deflambda" - it gets put on the channel that go returns


if nobody uses the channel go made, that value won't get used


hmm so if I wanted to return just the map, do I need to wrap the go block in take!


(take! (go
    (let [firstThing (<! myChan)
          secondThing (<! otherChan)]
      {:f firstThing :s secondThing})))


take is also async, it returns nil


like I said, async is contagious


there's no easy way out of async into normal values - in some cases no way?


I’m pretty sure that you’re going to need to use inside that deflambda


you can fake it by chaining all your other non-async code in a function in a go block (or call all your other non-async code from a callback on take, which is equivalent)


with lambda you either need to use a callback (like done!) or you need to return a promise


the aws context will not understand an async channel, so I think if you use async, the easier thing to do is use the completion callback


thanks @lee.justin.m, is this what you mean?

(deflambda run-lambda [ctx]
  (take! (go
    (let [firstThing (<! myChan)
          secondThing (<! otherChan)]
      (ctx/succeed! {:f firstThing :s secondThing})))))


but for some reason on AWS it's giving me the error, ""Cannot read property 'call' of undefined"


I forgot to remove that take!, and also ctx is the second argument


(deflambda run-lambda [args ctx]
  (println args)
  (println ctx)
    (let [firstThing (<! myChan)
          secondThing (<! otherChan)]
      (ctx/succeed! ctx {:f firstThing :s secondThing}))))


When print a multi-line string in the REPL, it ignores whitespace indentation. But if I call a function on that binding, the white-space is included. How is this typically handled?

(def multline "aaaaaa

=> "aaaaaa\nbb\ncccc"
(frequencies multline)
=> {\a 6, \newline 2, \space 30, \b 2, \c 4}
(frequencies "aaaaaa\nbb\ncccc")
=> {\a 6, \newline 2, \b 2, \c 4}


the default printed form escapes the newlines if that's what you mean? - if you use print on it you'll see a multi line output


oh wait - the spaces


yeah πŸ™‚

Alex Miller (Clojure team)22:03:32

may depend on what kind of repl you’re using too


yeah, I can't reproduce that in clojure.main


i see. I'm using Cursive's default (nrepl)

Alex Miller (Clojure team)22:03:01

I think that’s a quirk of nrepl stdin handling


seems like a bug πŸ˜„


I also can't reproduce with lein repl


REPL-y 0.3.7, nREPL 0.2.12


CIDER handles this correctly

user> (def multline "aaaaaa
user> multline
user> (frequencies multline)
{\a 6, \newline 2, \space 30, \b 2, \c 4}
but i think we format the output when we get it back to do this. i remember fixing a bug having to do with \cr on windows i think


wait, that repl doesn't use the pr form of the string?


or maybe =r


that's weird


I'm not really sure what version of nrepl I'm using πŸ™‚ I'm on OS X (Sierra), Cursive, Clojure 1.9, lein app template


I have a workaround to use a collection of strings and a simple function I found on stackoverflow:

(defn long-str [& strings] (clojure.string/join "\n" strings))
(def multi (long-str "aaaaa"


but that does make me a bit fearful of using multiline strings in the future


@jonjanisch: if you start lein repl in a terminal it shows the nrepl version


REPL-y 0.3.7, nREPL 0.2.12


same as yours


but perhaps Cursive bundles its own version of lein


might be a good question for #cursive


I see 0.2.12 in my IntelliJ dependency tree


hmm. for (pr multline) this message comes back from nrepl

  id         "53"
  session    "324621db-cd95-4b19-a5b7-e1676de7e861"
  time-stamp "2018-03-04 16:27:26.190502726"
  out        "\"aaaaaa\\n               bb\\n               cccc\""
and for just multline we get
  id         "54"
  session    "324621db-cd95-4b19-a5b7-e1676de7e861"
  time-stamp "2018-03-04 16:27:28.448696117"
  pprint-out "aaaaaa


pr-str is likely a better comparison (it's the string pr would output)


I'm starting to question the legitimacy of my asking questions in #beginners, since I've been doing this for a few years now, but... beginner's mind? Sure, that'll do. & I didn't have any luck with this one in #clojurescript πŸ˜‰ In clj it's easy to extend a protocol to all types of maps (ArrayMap, HashMap...) by extending it to the interface java.util.Map. That's nice because it spares you the hassle of extending it to each map type separately. As far as I can tell, I can't do the same in cljs by extending the protocol to cljs.core/IMap, because there's not a reified interface for cljs protocols. Is that correct? And is there any other way to do the equivalent in cljs?

Drew Verlee01:03:16

Yes, when do you ascend to #clojure?


Depends how clueless I feel on any particular day πŸ˜†


But if anyone has any thoughts on any sort of workarounds or alternate approaches, I'd really love to hear them -- I hate to only extend what I'm doing to concrete types, because then if a user creates a type that implements IMap, they won't automatically be able to use my protocol functions πŸ˜•