This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-11-03
Channels
- # beginners (167)
- # boot (22)
- # chestnut (3)
- # cider (9)
- # clojure (107)
- # clojure-berlin (1)
- # clojure-greece (3)
- # clojure-italy (6)
- # clojure-losangeles (6)
- # clojure-russia (8)
- # clojure-spec (71)
- # clojure-uk (42)
- # clojurescript (186)
- # community-development (1)
- # core-async (12)
- # core-typed (1)
- # css (15)
- # cursive (29)
- # data-science (11)
- # datomic (8)
- # defnpodcast (28)
- # duct (2)
- # fulcro (169)
- # graphql (6)
- # hoplon (3)
- # jobs-discuss (1)
- # kekkonen (5)
- # leiningen (11)
- # lumo (7)
- # off-topic (14)
- # om (1)
- # other-languages (14)
- # portkey (7)
- # re-frame (27)
- # reagent (14)
- # remote-jobs (1)
- # ring-swagger (5)
- # rum (15)
- # shadow-cljs (52)
- # spacemacs (59)
- # specter (78)
- # test-check (3)
- # vim (9)
- # yada (23)
Hello guys, just a quick question about case
, I tried to make this code working but I haven't succeed
(let [contact-status (case (lib-int/parse-int-or-nil status)
(:won all-statuses) (:current-client contacts/all-statuses)
(:lost-project all-statuses) (:lost-opportunity contacts/all-statuses)
(:lost-invoice all-statuses) (:ex-client contacts/all-statuses)
nil)]
Each test condition evaluates to a different number however I am getting Duplicate test constants
. Does anybody know why is that? I've read documentation and I know that constants must be compile-time literals but I am not sure what exactly it means...is it that all conditions are actually a "quoted" list so I need to use cond
?Solved it with (condp = status)
, is there a better solution?
@schmee It might change but it will moreless stay the same
you can also take a look at multimethods: https://www.braveclojure.com/multimethods-records-protocols/
and core.match
if you want full-fledged pattern matching: https://github.com/clojure/core.match
Ok, thanks - btw I looked at core.match but I didn't want to introduce new dependency just for matching in one functin 🙂
but nevertheless it looks nice
@petr.mensik compile-time means that you have to use constatnt expressions (numbers, strings, symbols, keywords, etc.) anything that has unknown value during compile time is not acceptable
@jumar yep, I just wanted to make sure I really got it 🙂
if you want to dig deeper check this screencast: https://www.youtube.com/watch?v=_f3WeoDSN-I
@petr.mensik case is weird, for example
user=> (case 2 (1 2) :OK)
:OK
- it uses () in a way pretty much nothing else does in clojure, as a grouping construct rather than a function call syntaxin fact, it’s one of the only things I would change about the clojure special forms if I were re-implementing the language, because it’s such a weird special case
is there anyway to improve the error message from clojure.spec?
(spec/def ::document (spec/keys :req-un [::number ::type]))
example (spec/assert ::document x)
be “the document field is missing” or “the number field is missing in document”@rcustodio there's a thing called explain-data
which gives you back a datastructure that a tool might use to make really nice output
Okey, thanks, and do you know if there’s someway of use db validation? (like field x exists)
you can use stuff to validate things going into the db or coming from the db. However, defined spec should be side-effect free. Like don't write a spec that checks for the existence of something in the database, that would be turrible
is there anyway to convert (clojure.core/fn [%] (clojure.core/contains? % :type))
to string
(str '(clojure.core/fn [%] (clojure.core/contains? % :type)))
:)
hey all, can I ask a beginner question
I have some code where I have a string and an empty vector. I want to basically map over the string and put each character into the vector. In this code I create a string and an empty vector. Then I loop over the string with "doseq" and save the character into my vecotor. However, when I print the vector at the end of the program, it is always empty! For example, this code: (def stringo "HelloO") (def saves []) (doseq [x stringo] (println x) (conj saves x)) (println saves) prints this for me: H e l l o O [] And similar code using "let" returns the same thing: (let [stringo "HelloO"] (let [saves []] (doseq [x stringo] (println x) (conj saves x)) (println saves))) So my question is basically 1) Why does it print an empty vector instead of a vector containing all the characters? and 2) How should I decide whether to use def or let in situations like this? Thanks!
@derpocious conj does not change the vector
it returns a new vector, with your addition applied
you need to use that vector, with a case like yours you could use reduce to add the new item at each step
unless this is just an exercise, you can use into, which is already conj inside reduce plus some other features
strings are collections in clojure so you can "pour" it into another collection with (into [] "hello world")
or just look at it sequentially with (seq "hello world")
but the version using conj is (reduce conj [] saves)
for reference
@derpocious do you understand why it didn't change your var saves
? Want to make sure it was clear what was going on
hmm so there is no way to reset the saves vector?
it’s not mutable
usually that means you want to think about it differently. especially when learning clojure, you want to get away from thinking about mutating
@derpocious In non-Clojure languages, you normally copy a string into an array using the exact style you did: define a couple variables, then go through a loop modifying those variables. Clojure and other functional languages don’t do it that way, and in fact they don’t even think that way. In Clojure, you pass values into functions that give you back new values. So in Clojure you’d say, “Here is an immutable string value, please give me back the corresponding vector (array) value.”
and that probably sounds infuriating, but what question are you answering with this bit of code. we can design a function that answers that question without the mechanics of changing a variable a bunch
Hmm ok. That sort of makes sense.
I want to make a function that takes a string and returns a vector of the characters that occurred more than once.
That sounds fun 🙂
so there's several ways to do it. some that are kinda cheating since the language itself offers tools very close to that
but let's do one that's a little more manual to learn how to keep and accumulate state
as we're going down this string, we need all of the character's we've seen so far. and if we haven't seen the character so far we add it to the set, right?
wait, are you using a separate set to keep track of ones youve seen and the return set?
or just one?
the question isn't just to return distinct letters, return only the letters that occur more than once.
so imagine we have a function that takes two arguments. the first argument has the two sets in it. seen and seen again. and the second argument is the character we're considering
ok, and if it's not in seen, add it to seen, right
and we'll use clojure sets since those are convenient for us. they're one of the fundamental data types and they'll make it easy to not worry about deduping
but I should use reduce for this?
hmm idk I like doseq because it seems like just a normal loop over the collection
I’d recommend loop/recur
Just because it’s closer to what you’re likely familiar with
if you are consuming a collection reduce is always better than loop/recur, it’s clearer, more concise, and performs better
reduce is the better way to do it programmatically, but loop/recur may be easier to understand in the early stages of learning Clojure
doseq is only useful for side effects, you can’t collect values from it
ah ok
but can reduce take a collection and return a collection?
the reason i like reduce is because reduce means reduce a collection down to a value. so when you want a set of the duplicated letters i'm gonna do that
reduce can take a collection and return pretty much whatever you want to get 😉
and what makes reduce stand out to me in this case is that reduce uses a function who's signature is two arguments: the result from previous calls of the function and the next element in the collection. So it's "the result of what we've considered so far" and "what to consider now"
and the body of the function is how to merge the current element into the result of what we've considered so far
@derpocious does that give you enough to try to write the function on your own?
I think so
Thanks a lot guys 👍
#{}
. clojure makes data types really easy to make. and you can make a vector with []
. So if you want a vector with two sets in it you can just write [ #{} #{} ]
cool. So #{} is a hash set? I remember learning there is also sorted set. Are there other kinds of sets?
there is a sorted set but you need to load the library that provides it. so don't worry about that for right now. there are lots of custom data types out there but the vast, vast majority of clojure code is written with the few data structures: hashman {}
, hashset #{}
, vector []
and sequences
I am having trouble breaking into the Functional Programmer mind set for the following:
function eventHandler (e) {
let x = e.target.offsetHeight
let y = e.target.offsetWidth
if (condition) {
x += 10 //update value
y += 15 // update value
}
doSomethingWithSideEffects(x, y)
}
The above has local mutating state. This is not cool in Clojure, but how would clojure solve the above problem? Its not reducing over anything, so can't use that, and no need for recurr. Would the best solution be to create a function thats used in eventHandler
which would return either the original x and y
or a modified x and y
?sorry, just updated. Both x and y will likely be different
(defn get-dimensions [e]
(let [height (.. e target offsetHeight)
width (.. e target offsetWidth)])
(if condition
[(+ 10 height) (+ 15 width)]
[height width]))
(let [[height width] (get-dimensions e)]
(compute (stuff x y)))
That feels along the same lines of what I wanted to do. Good example and thank you!
i'm making a CRUD app as my first project to familiarize myself with both backend and CLJS/reagent - i'm having a silly problem that's probably something simple i'm missing, i was wondering if someone could help?
when the server receives a POST request to a certain endpoint, if there is no table with the same name as the id param, we create it
but it seems my when-not is not working... this is an abridged version of my server file:
the create-table
function... it tries to create the table even when it already exists
do you know how to get a repl up and running? Can you call db-exists?
on a table you know already exists and see what it is returning?
put a println statement there in the when-not function. and let's see what value name has there. i might imagine that there's a type mismatch going on. perhaps the id is coming in in a slightly different format than you expect
im using VS code with parinfer and the repl plugin for now... not ideal but i figured i would switch to cursive/light table after learning more
don't worry about that. some people really like the VS code setup. do what works for you.
(defn create-table
[name]
(do
(println "hua"
(when-not (db-exists? name)
(sql/db-do-commands spec
(sql/create-table-ddl name [[:comment "varchar(120)"] [:time :int]]))))))
that's crazy. well this is a way you can get some introspection into your apps. using the repl and such
PostgreSQL only respects case if you wrap entity names in double quotes.
BTW @U621RMVAN This opens you up to a SQL injection attack:
(sql/query spec
[(str "select count(*) from information_schema.tables where table_name='" name "'")])
because you are constructing the SQL via string concatenation. You should use query parameters like this: (sql/query spec
["select count(*) from information_schema.tables where table_name = ?" name])
That is much safer.p.s. Happy to answer any questions you may have about clojure.java.jdbc
-- I'm the maintainer!
#(str (:pred %1))
returns "clojure.lang.LazySeq@6c40fb0f"
how to make it return the right lazyseq?
#(str (pr-str (:pred %1)))
oh oops
#(pr-str (:pred %1))