This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-04
Channels
- # beginners (149)
- # cider (1)
- # clara (12)
- # cljs-dev (226)
- # cljsrn (2)
- # clojure (275)
- # clojure-russia (5)
- # clojure-uk (14)
- # clojurescript (57)
- # cursive (23)
- # data-science (15)
- # datomic (1)
- # fulcro (8)
- # hoplon (9)
- # onyx (5)
- # portkey (15)
- # protorepl (1)
- # re-frame (8)
- # reagent (17)
- # shadow-cljs (22)
- # uncomplicate (13)
- # vim (36)
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: https://www.braveclojure.com/foreword/
also, a new version of Programming Clojure was released just last week: https://www.amazon.com/Programming-Clojure-Alex-Miller/dp/1680502468/
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
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)
you might want to read the Java section of http://xahlee.info/comp/clojure_is_hard_to_learn.html
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
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!
@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 😄
@schmee I would say the hardest background to come to Clojure from is one that has only ever known Java-style OOP 🙂 /cc @noisesmith
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.
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?
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?
Yeah powershell isn't happy about that either
Are there instructions on what the ~/.lein directory shoudl look like at the end? I can download the file and place it myself
Or does lein self-install
take any additional flags?
$ tree ~/.lein/
/home/justin/.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
Thank you!
the only file you actually need is a single jar under self-installs/ the rest are optional / automatically created
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?
Awesome, that worked. running the repl now.
On another topic, is there a favorite container base image that people tend to use for clojure projects?
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]
(do
(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
Cheers!
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]
(do
(println "count" (count (.-ids data))))
(count (.-ids data)))))
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]
(do
(println "count" (count (.-ids data))))
(count (.-ids data)))))
(deflambda run-lambda []
(doStuff))
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
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 []
(doStuff)
(go
(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?
oh wow
I’m pretty sure that you’re going to need to use https://nervous.io/doc/cljs-lambda/cljs-lambda.context.html#var-done.21 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]
(doStuff)
(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"
huzzaaaah!
I forgot to remove that take!, and also ctx is the second argument
(deflambda run-lambda [args ctx]
(println args)
(println ctx)
(doStuff)
(go
(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
bb
cccc")
multline
=> "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
may depend on what kind of repl you’re using too
yeah, I can't reproduce that in clojure.main
I think that’s a quirk of nrepl stdin handling
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
bb
cccc")
#'user/multline
user> multline
aaaaaa
bb
cccc
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 thinkwait, that repl doesn't use the pr form of the string?
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"
"bb"
"cccc"))
@jonjanisch: if you start lein repl in a terminal it shows the nrepl version
might be a good question for #cursive
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
bb
cccc
"
)
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?
Yes, when do you ascend to #clojure?
Ah, confirmed the non-reification at https://clojurescript.org/about/differences#_protocols
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 😕