This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-07-26
Channels
- # aleph (1)
- # beginners (96)
- # boot (5)
- # cider (44)
- # cljdoc (11)
- # clojure (73)
- # clojure-conj (4)
- # clojure-dev (1)
- # clojure-finland (2)
- # clojure-italy (7)
- # clojure-new-zealand (1)
- # clojure-nl (3)
- # clojure-spec (4)
- # clojure-uk (66)
- # clojurescript (114)
- # code-reviews (16)
- # cursive (15)
- # datomic (37)
- # emacs (6)
- # events (2)
- # figwheel-main (12)
- # fulcro (36)
- # graphql (19)
- # hoplon (2)
- # hyperfiddle (3)
- # jobs (2)
- # leiningen (4)
- # off-topic (36)
- # om (1)
- # om-next (2)
- # other-languages (1)
- # re-frame (12)
- # reagent (12)
- # reitit (5)
- # remote-jobs (4)
- # ring (2)
- # shadow-cljs (218)
- # spacemacs (8)
- # specter (7)
- # sql (34)
- # tools-deps (9)
- # uncomplicate (6)
I thought that would be it, but I'm probably going about this all wrong. I have these macros:
(defn wrapper [m f]
(f m))
(defmacro operation [f]
`(wrapper ~f))
(defmacro expand-operations [m & ops]
`(~m ~@(map (fn [op] (list `operation op)) ops)))
I'm effectively trying to insert the thread-first into the result of macroexpanding expand-operations.(and wrapper
takes two arguments -- you're only giving it one argument in the operation
macro)
expand-operations
doesn't do what my end goal is, so it may be the wrong approach. I'll back up.
I have the following:
(-> request-data
(operation-wrapper operation1)
(operation-wrapper operation2))
operation1
and operation2
are functions that accept and return maps:
request-data
is an initial map.
operation-wrapper
is a function of the form (fn [m f]). It checks m
for an error value, and returns m
if an error is found, or else it executes (f m)
.I'm trying to write a macro, let's call it thread-operations
that would produce the code above as follows:
(thread-operations request-data operation1 operation2)
So, (defmacro thread-operations [m & ops])
would be the definition.
(reduce operation-wrapper request-data [operation1 operation2 .. operationN])
like that?
Sorry, simplifying since operation-wrapper
already accepts [m f]
Macros should generally be considered a "last resort". In real world Clojure, they're very rarely used.
Write everything with functions first, if you can (and you nearly always can), and then add a macro for "syntactic sugar" if necessary.
Hmm, yes I think reduce is the answer here. I never use macros because I find I can do everything I'm trying to do without them, but as such, I've never learned them past the most basic concepts. I thought I finally found a case where they might be useful, but I guess not. Thanks for the advice!
Is there a Clojure(Script) screencast channel that focuses on live coding, so that I could watch & learn from more experienced people solving problems using Clojure? Something like http://www.parens-of-the-dead.com/ but more recent? Thanks!
https://www.youtube.com/user/raphaelyaakov/videos or maybe https://www.youtube.com/watch?v=_f3WeoDSN-I&list=PL-izX-5c9Z5TRqH7uVhWMq3ZJxR8PmExb
yes, clojure pills looks nice though not exactly what I imagined
I'd love to see the Clojure-equivalent of Edward Kmett's live coding sessions :- D https://www.twitch.tv/ekmett
I thought about streaming my learnings on Twitch the other day. Just need to find time to get set up.
Thanks! I actually burst out laughing when I saw my channel posted here, since I'm pretty new myself and make videos primarily to document my own learning.
@U8LB00QMD they're fun so keep up the good (work)
😄
Hello all, is there any way to use dynamic predicate? Like (filter #(or <predicates-list>) collection)
?
Perhaps (filter (fn [val] (some #(% val) predicates) col)
?
Nice! I didn't know that one.
@holyjak -- there are lectures in these videos, but have you seen https://purelyfunctional.tv/
What's the best way to make sure a program runs some clean up code at the end, before it exits?
Would using something like this be a bad thing? https://github.com/hypirion/beckon
What’s the best way to run bernoulli trials in clojure? I can do something like:
(defn bernoulli
[p]
(not (empty? (random-sample p [true]))))
(repeatedly 10 #(bernoulli 0.5))
But it seems like there’s probably a better way?@holyjak have you taken a look at https://www.youtube.com/channel/UC1UxEQuBvfLJgWR5tk_XIXA/videos ? they do a joint repl programming session while explaining their work in the back half of every episode
thanks! I guess that is what I have been looking for!
@UANK2VBHA Looks like the episode is off for today (scheduling challenges)
Not really sure how to use doc
with functions in other libraries. Trying to see the documentation for clojure.spec.alpha/gen
, would have expected to type something like (doc :clojure.spec.alpha/gen)
, but that’s not working.
Also tried to require…no joy:
user> (require '(clojure.spec.alpha))
nil
user> (doc gen)
nil
@dcreno (doc clojure.spec.alpha/gen)
or
(require '[clojure.spec.alpha :as s])
(doc s/gen)
I know I tried that, I wonder if I needed to require
first?
You tried (doc :clojure.spec.alpha/gen)
-- with a keyword argument.
(unless you typo'd it in your message)
tried both…
Yes, you must load a library first.
that’s it then, tried the right way but hadn’t loaded the library first.
doc
reads metadata from the Var for the symbol -- so you won't see anything until the symbol is actually defined (which happens when you load the namespace).
does the library/file/class/whatever need to be downloaded to a particular location? I use lein
but I don’t know where it downloads to and if it can always be loaded by the repl.
asking because
user> (require '[clojure.spec.alpha as s])
FileNotFoundException Could not locate clojure/spec/alpha/as__init.class or clojure/spec/alpha/as.clj on classpath. clojure.lang.RT.load (RT.java:463)
user>
ah, that was an as
instead of :as
.
Everything downloads dependencies to your local Maven repository cache (in .m2
in your home directory -- but you should pretty much never need to look in there).
@dcreno there's two things going on here, that are combined in other toolsets but isolated here.
there's a directory where various dependencies are stored, and then a config that decides which versions and which ones are visible to your process
so, with most languages you do a global install, and that version of that lib is available to all processes
with maven based deps (which lein, boot, clj etc. all use), you have a shared cache that can have any number of versions of each dep, and a startup config that decides which versions of which deps are visible
Thanks for the background. Any further reading you’d recommend on this topic? Trying to understand differences between what lein ring server
has access to (for a ring base app) and what I have access to in the spacemacs cider repl. Still a little fuzzy to me the process of getting files, loading files, referencing namespaces.
The leiningen docs might help. The basic idea is that project.clj decides which deps are looked for. If they are not already in the ~/.m2/repository/ cache they are downloaded (recursively for nested deps)
cider should see all the same deps if you point it at the right directory
but it's a per-process config, so if you started cider from a different project, or with a no-project bare repl, it won't see the same deps or at least not the same versions of the deps
so i was just reading about the reduce function which seems pretty great. An example was (reduce + [1 2 3]) to add the elements of the vector together. however, i can't figure out how to make this generic so that it would add up all the elements of a vector without knowing the initial size of it. any help on how i would do that or at least how i would look up and interpret the docs to learn how to do it myself?
you are likely looping over the vector index wise, instead of using a seq of the vector
seqs are like a functional version of an iterator, iterators have something like a hasNext method and a next method, seqs have first and rest
@chase-lambert I'm not sure if I understand that question - reduce already accepts collections that are not pre-counted, by producing a seq over them
so i was trying something like (defn sum-vector [[vector]] (reduce + [vector])) but i can't make that work. the best i've done is adding up 2 or 3 items from the front of the vector.
maybe i don't know how to say this will take a generic vector as a parameter or something super fundamental like that.
Try (defn sum-vector [vector] (reduce + vector))
You can then call that function as: (sum-vector [1 2 3 4])
If you would prefer a different definition that allows you to make calls like (sum-values 1 2 3 4)
, that can be defined, too, slightly differently.
lol! that totally works. i knew it was going to simple! oh man. so vector is an actual word that means generic vector doesn't it?
in a binding vector it shadows the actual meaning
it's a function that makes a vector out of some args, normally
vector is a parameter name that could be anything, e.g. (defn sum-vector [x] (reduce + x))
is the same function in behavior.
You could try calling it with (sum-vector 5)
, but it would give an error because (reduce + 5) is an error.
[x] doesn't mean "x is a vector", it means "take whatever x is, and put it in a vector"
right, see above
so if you have (def x [1 2 3])
[x]
is [[1 2 3]]
but in an arg list [x]
means "take the first element out fo this argument, and call it x"
(destructuring)
You may wish to save destructuring for a later day of learning, perhaps.
(ins)user=> (defn weird-first [[x]] x)
#'user/weird-first
(ins)user=> (weird-first '(1 2 3 4))
1
- right - it's a feature that was used accidentally here, I thinkthat's a good idea to just ignore it for now
but that's why your [[vector]] args were not an error - the compiler thought you were using the destructuring feature
ahh! destructuring. yeah i've already read that section of the Brave book 2-3 times. hasn't quite clicked yet.
(defn fn-name [x] <body of fn-name here> )
means to define function fn-name
that takes exactly one parameter. Replacing [x]
with [x y]
would mean to define fn-name
to take 2 parameters instead.
Those parameters can be values of any type, e.g. lists, vectors, numbers, strings. Clojure doesn't need (or usually even allow) to say what those types must be. The code in the body of the function definition often makes assumptions about what types of values it supports.
"but in an arg list [x]
means "take the first element out fo this argument, and call it x" "
that just cleared up some confusion for me.
i got a quick random question. when i'm playing around with set creation and such, my return value re-orders the items in the set. so (hash-set :a :c :d} becomes #{:c :d :a} and (hash-set 1 2 3 4) becomes #{1 4 3 2}. What is the implications of that? Is it something I should be considering when creating sets?
sets are not ordered
this also goes for hash-maps
so that means you shouldn't use them in code that relies on order of items in collections (but they are good for code where the question is "does this item exist in the collection")