This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-11-16
Channels
- # aleph (1)
- # announcements (3)
- # babashka (24)
- # beginners (333)
- # clj-kondo (36)
- # cljs-dev (11)
- # clojure (75)
- # clojure-italy (3)
- # clojure-uk (15)
- # clojurescript (31)
- # core-logic (18)
- # cursive (2)
- # data-science (3)
- # datomic (1)
- # events (1)
- # fulcro (13)
- # graalvm (2)
- # jobs (1)
- # kaocha (2)
- # malli (1)
- # overtone (6)
- # re-frame (7)
- # reagent (17)
- # rewrite-clj (3)
- # shadow-cljs (10)
- # sql (9)
- # vim (1)
I’ve been using a lot of Elixir, and in that language you can use pattern matching to dispatch to different implementations of a function depending on the arguments. In my case right now, I just want to dispatch based on whether the first arg is a string or a list. What’s the standard way to do this?
Both multimethods and protocols seem like too much for what I’m trying to do. I assume there is something simpler?
Is this preferred for something this simple?
(defn something [arg]
(cond
(str? arg) arg
(list? arg) (other-fn arg)))
that is fine, although it is string? not str? and seq? or sequential? is likely what you want not list?
but I would avoid that kind of thing, a function where an arg can be different types
I mean it is weird to have a function that takes a string or a list as the same argument
the only thing I would thing if is some really annoying apis will return a string value instead of a list containing one string
I would undo that as soon as possible, meaning take the api response and box it in a vector if it is not already a list
I guess I’ll do that, but I was more interested in learning a general lesson rather than solving this specific problem
and box
is a fairly common function to write, and it looks sort of similar to your something
function
ring middleware is kicking my ass 😄
I want to check if the session variables are set, if so give you the app, if not give you the login screen
but I get lots of Null Pointer Exceptions ;-;
@chrysalis129 feel free to ask your beginner questions here. I have to ask : is this a class homework problem? I've seen several people ask for help with the exact same problem in various places.
yes it is its an assignment due on sunday 😧
if anyone can help me with debugging this that would be great
That explains why your class mates are all posting the same question then 😁
I'm eating right now but will be happy to help later -- or any time over the weekend
ok sounds good 🙂
Seems like everyone is struggling with it. Makes me think maybe the teacher isn't doing a very good job ...
yea the prof usually only teaches syntax when it's not relevant to an assignment.. plus he often goes on tangents during lectures so it's hard to pay attention
first assignment he gave = super easy and now this one super hard 😧
I sympathize -- my first year comp Sci prof was terrible 🙃
it's not i got most of the functions to work but cities doesnt print all the csv values anymore and i'm trying to find a way to do closest-city-pairs without the use of ->>
also theres another function i need to implement
its to take all the :population key values from all the hashmaps in cities and sum them up some how
im trying to map the populations to a vector but it doesnt seem to want to print too
(defn total-population [cities] (for [x (map :pop (cities)) :let [y x]] (print y)))
You have parens around cities
-- are you passing in function?
cities returns the hash map of each row in the csv file
Sorry I’m down to help and explain but I still don’t see a question or what you working. Just the whole file
ok nevermind i got the total population working
now for the last function i need to do
i need to print :province and :pop from all the hash maps in cities and sort them in order from smallest :pop to largest
any idea where i can start with that?
sort-by :pop
how would i go about printing just :province and :pop from cities(returns a vector of all hash maps in a csv file))
also is there anyway to complete this function without using ->> and (filter large) dpsutton if i might ask?
Because theres a thread with the solution on reddit and i feel all my classmates are going to copy it so I want to find a different way to do the function
(defn closest-city-pairs [] (let [y (->> (cities) (filter large) vec)] (for [a (butlast y) b (rest y) :when (and (not= a b) (close a b))] [(:city a) (:city b) (distance a b)])))
i tried doing it this way
Well you can remove the vec and just use (filter large (cities)) but I think the for loop is the more tell tale expression there
but i get unsupported binding form :when
yea it is lol
What is your current version? Let’s see what’s up with the :when binding error. If I had to guess you’ve got that in the let rather than the for
In that for
comprehension you're going still compare N-2 of those cities against themselves so I don't think you're saving much with butlast
and rest
-- you already need (not= a b)
so you might just as well do (for [a y b y :when (and (not= a b) (close a b))] [(:city a) (:city b) (distance a b)])
(since close
calls distance
anyway and just checks it against 600
, I'd probably have :let [d (distance a b)] :when (< d 600)
inside the for
and then [(:city a) (:city b) d]
in the body of it)
(or have a predicate near?
that takes a distance and check it against 600km: (defn near? [d] (< d 600))
-- then :when (near? d)
in the for
per above)
Lots of ways to write it.
Per @dpsutton’s comment above, since you're using for
and it only cares about sequences, you definitely don't need to call vec
on the filtered sequence of cities:
(defn closets-city-pairs []
(let [large-cities (filter large (cities))]
(for [a large-cities b large-cities
:let [d (distance a b)]
:when (< 0 d 600)]
[(:city a) (:city b) d])))
Something like that?thanks that helps
okay now for some reason the distance between two cities isnt accurate anymore
nevermind it works fine scratch that
You can use Pythagorean triples so the distances are nice easy numbers. (0,0) and (3,4) will give you a distance of 5
how can i get print out a vector of hash maps that just returns the :province and :population
if i have cities function that returns the vector with all the hashmaps and keys
select-keys
will help
Also, if you want to map
a function over a sequence and get back a vector instead of a sequence, you can use mapv
(there's a filterv
as well)
ok but i need to iterate over a vector with multiple hash maps.. how do i just get the :pop and :province
select-key doesnt seem to work if i try to pass (cities) into it
(mapv #(select-keys % [:pop :province]) (cities))
(map inc [1 2 3]) will call inc on each item in the vector. Likewise you want to select keys for each map
@chrysalis129 Some good advice about map
and functions https://stuartsierra.com/2015/08/10/clojure-donts-redundant-map (when you're ready to think about idiomatic code as opposed to just working code).
okay thanks
ill take a look
i tried this
(print (mapv #(select-keys % [:province :pop]) (cities)))
it seems to only be returning the :pop for each tho
Are you sure that all the city maps have :province
as a key?
o true lol
had it as :admin
for some reason
Administrative Region 🙂
Yeah, I've seen that coming back from Google Geo APIs.
okay so it prints like this
{:admin Nunavut, :pop 0}]
is it possible to get rid of :admin and :pop so it just prints the values?
also i tried sorting it in terms of population
(print (mapv #(select-keys % [:admin :pop]) (cities)) (sort-by :pop))
its giving me wrong number of args passed thgo
(mapv vals coll)
will give you sequences of just the values from hash maps
You might not always get them in the same order tho' since hash maps are unordered. If you always want :admin
then :pop
, you might look at the juxt
function
(mapv (juxt :admin :pop) (cities))
will give you a vector of vectors, each subvector containing the :admin
value, followed by the :pop
value.
okay yeah that works
thanks
ok it goes from largest population to lowest
where do i put sort-by to flip it?
You can either sort the city collection, then map over and select just the two fields, or you can do it the other way around.
In the first case you would sort-by :pop
since you have hash maps with the key :pop
In the second case you would sort-by second
since you now have vectors with the population in the second position
How is 20%
represented @haiyuan.vinurs ?
(if it's just an integer -- 20
-- you can just divide by 100
, or by 100.0
if you specifically want a double
result rather than a ratio)
ok i tried doing the first option sean
its saying im giving the wrong number of inptus tho for my function
(defn provincial-population [] (let [y cities] (sort-by :pop) (mapv (juxt :admin :pop) (cities)) ))
(sort-by :pop coll)
<-- needs a collection
Remember that Clojure is a) expression-based and b) all immutable. Sorting produces a new collection that is a sorted version of the input collection.
@seancorfield i read the string 20% from file, so i need to parse it
So you're either going to have (sort-by ... (mapv ... (cities)))
or (mapv ... (sort-by ... (cities)))
->>
can make the order of operations clearer, if you want.
@haiyuan.vinurs so you have "20%"
as a string?
ok i got it to print
but its still doing largest populations first
(defn provincial-population [] (let [y cities] (sort-by :pop (mapv (juxt :admin :pop) (y))) ))
@chrysalis129 Read what I said above about the order of sort and select keys. You're trying to sort on :pop
after you've produced a vector of vectors.
@haiyuan.vinurs are you guaranteed all the values are <some sequence of digits> always followed by %
? If so, you could just do a substring operation to remove the last character, then parse it as a long, then divide by 100.0
(Long/parseLong "20")
will produce 20
, for example.
Much love to you guys here 🙂
finished my assignment
this is a great place
Assignments are never "finished" 🙂
Let us know how the marking goes on it.
I will 🙂 thanks again
actually im not done my apologies -_-
i just realized we have to sum up each province because theres hash maps with the same province
You can write a helper fn map-vals
that take a fn and a map and returns a new map with the fn applied to each value in the input map. Like this:
(defn map-vals [f m]
(into {} (map #(update % 1 f)) m))
You then have to group the cities by province and use map-vals to turn those collections of cities into the sum of population, then sort that. Like this:
(->> (group-by :province cities)
(map-vals #(apply + (map :pop %)))
(sort-by (comp - val)))
This will give you provinces sorted in decreasing order of population.the function isn't allowed to have any parameters unfortunately 😧
Who's restricting you from having parameters on that function?
and then sort that
i think ill need a for loop yea?
(defn distinct-provincial-population [] (for [[p xs] (group-by :province (cities))] [p (reduce + (map :pop xs))])) is what i got so far
any ideas how to proceed from there
Sounds about right -- but isn't it :admin
rather than :province
?
Hi, everyone I keep running into a problem with records and protocols : We have a couple of protocols in separate namespaces, the record implementing those protocols resides in a separate ns. Whenever I uberjar and import it as a lib in another project it gives the exception : *no impelmentation of method ... of protocol ... found for class*. Is there sth I am missing about protocols & records? Does it have to do with which ns s are imported where I am using them?
Probably. You need to load (require) any namespaces that contain implementations before you can use them
I imported the record and the exception went away. (The namespace containing the implementation was already require
d). Do I always have to import the record or there is some other thing at work here?
It depends what you’re doing but you should not generally need to import
I have a middleware for checking logins, I want to check the session variable and redirect to login if it's not set
but i'm stuck in an infinite loop of login checking middleware
actually it seems to work now but i keep getting null pointer exceptions on RegEx matches
I'm having a beginner moment. Why does the following always return "dunno"?
(defn color->name [color]
(case color
"#ffffff" "white"
"#000000" "black"
"dunno"))
Using a switch case in Java "works". How is Clojure seeing the "#" differently?
try it without the dunno and see if you get "no matching clause"
Actually your code works for me when I put in "#ffffff"
jpdrills.server=> (defn color->name [color]
#_=> (case color
#_=> "#ffffff" "white"
#_=> "#000000" "black"
#_=> "dunno"))
#'jpdrills.server/color->name
jpdrills.server=> (color->name "#ffffff")
"white"
jpdrills.server=>
Ok, so I just copy/pasted it again, and now it's working for me.
not your question, but why not just make a hashmap of it, then use that as a function?
@tws makes a great point, could you provide an example for our new friend?
I like that solution. I was just confounded why it wasn't working for me.
I found my problem!
Thanks for the help. 😀
Wow I was missing an end-brace in my one authentication handler
err it was misplaced in the map, the ending }
So yeah! don't pull out your hair if you have been working all day and you suddenly "break everything" you probably accidentally put an ending brace }
someplace inopportune and you can find it with clear eyes in the morning.
Is it possible to do (swap! jpc-users-atom update-in [email :kanji-stumbles] conj kanji)
and then simply do (swap! jpc-users-atom update-in [email :kanji-stumbles] disj kanji)
to remove one?
Swap just calls your function on the value of the atom. You can test everything outside of atoms and swapping and then know it will work in the context of atoms
can someone help me troubleshoot flycheck-clj-kondo? i've got flycheck installed (`M-x fly` brings up flycheck commands), I've got clj-kondo on my $PATH as evidenced by being able to fun it from the command line, but it's not doing any linting
and running clj-kondo --lint my-source.clj
returns 0 without seeming to have done anything
@tstirrat what operating system are you on? what do you see when you do which clj-kondo
and clj-kondo --version
?
➜ ~ which clj-kondo
/usr/local/bin/clj-kondo
➜ ~ clj-kondo --version
clj-kondo v2019.10.11-alpha
https://github.com/borkdude/clj-kondo/blob/master/doc/install.md#installation-script-macos-and-linux
hi i'm back
so i tried implementing this and have been trying to sort it from least to most
(for [[p xs] (group-by :admin (cities))] [p (apply + (map :pop xs))]))
but when i try applying sort-by in the manner i did before i get wrong number of args error
(for [[p xs] (group-by :admin (cities))] [p (apply + (map :pop xs (sort-by :pop)))]))
sort-by requires a key-fn for comparison
you could take the result you have from the for loop
and wrap that whole result in (sort-by > val ... )
basically it needs to know what you think matters for sorting
dont know what u mean
but i tried adding cities
but its still largest to smallest
flip the operator
which operator?
right, the order of operations works from inside-out, so if you want it sorted you need to put sort-by on the outside
ok i did
(for [[p xs] (group-by :admin (cities))] ((sort-by :pop (cities)) [p (apply + (map :pop xs ))])))
getting arrayseq cannot be cast to lang.ifn
is cities a (function)
?
what's the latest line of code you had that was working?
(for [[p xs] (group-by :admin (cities))] [p (apply + (map :pop xs))]))
nice, it has a result you like, but it's not sorted correctly?
its sorted from largest to smallest
need smallest to largest
what does the result look like my friend?
oh yea its not even sorted
it just lists the provinces
and their pops
it adds all the hashmap province populations correctly
just need to figure out where to put sort-buy
Excellent work so far
sort-by i mean
(sort-by second (for [[p xs] (group-by :admin (cities))] [p (apply + (map :pop xs))]))
Assuming you want to sort the pairs of province / population.
Say it out loud in words. “Once I compute the pairs of city name and counts, I need to sort by the population count”
thanks sean that did it 🙂
i see so like last operation that needs to be done goes on the outside
Right, because function arguments are evaluated before the function is called.
(sort-by second (for ,,,))
;; evaluates (for ,,,) first
;; then calls `sort-by` on the result of that evaluation
And what does Second do? just grabs the second parameter of each thang?
Yes, because we have a sequence of pairs (province, population)
Second in this case is the population ?
Ah okay awesome
(first pair)
=> province; (second pair)
=> total population (the sum of the population of each city within that province
So it's always a pipeline of operations, starting with the innermost and working outwards.
House.Price.Erase in clojure talk becomes (Erase (Price (House))) right?
Collection.Second.Sort-by (Sort-by (Second (Collection))) not a perfect mapping but maybe some good examples could help illustrate how functions bloom from inside out
I am not sure what language that is intended to be written in. If House.Price.Erase is written in Java syntax, and if the Clojure function price
takes a value of type House
and returns its price, and the Clojure function erase
takes a price value and does something with it, then yes, (erase (price house))
would be how you write it.
However the verb erase
you are using in your example makes me wonder whether it is intended to remove the field/property/attribute/whatever of the object house, in which case it is unlikely that you would write the Clojure code that way.
As Dan said above, say it out loud to get the order of operations -- and think about it as a single expression, rather than a sequence of imperative steps.
got it
mm that's true, functional does not rely so much on sequential procedure
but in the abstract what do you want this transformation on this collection to look like
ok so going back to a function i was doing previously
actually nevermind
i think im done 🙂
Rock n Roll
thanks for the help guys
I owe much of my sanity to the fine chaps here.
ill probably come back here when final exam season comes around 😛
And that function composition / call ordering is also why ->>
might make it easier to think about:
(->> (for ,,,) ; compute total population for each province as pairs
(sort-by second)) ; then sort by the second element of each pair
hey that's a great time to introduce thread-thru and double-thread-thru
so that makes it not about order of operations?
think of a spool of thread
its just an assignment
->>
thread-last takes the expression and puts it into the last slot of each "step" in order -- turning it into the nested function call you saw above.
clojure class would be Dope
class is about a bunch of programming languages
ok makes sense
Which other PLs are you studying @chrysalis129?
were doing scala next
and some other stuff
but clojure and scala most indepth
yea sorry bout that dps 😧
Well I’m glad that clojure is in curriculum somewhere :) good luck with your studies
thanks dpsutton 🙂
Scala is... interesting... I did that for about 18 months before switching to Clojure. Do you already know Java @chrysalis129?
Yea I do
know it a lot better than clojure thats for sure xd
also know python C++ node.js
trying to learn some other frameworks so i can get a software engineering internship soon
hello again I have one more question
say I have a one string that is "Hello" and a second string that is "Apple"
is there anyway I can evaluate these two based on alphabetical order something like (> firstString secondString) evaluates to true?
doesnt work
java.base/java.lang.String cannot be cast to java.base/java.lang.Number
i get -7
cant resolve doc
yea doesnt work either 😧
cmd with java -cp clojure-1.8.0.jar clojure.main filename.clj
ok thanks i got it to work xd
@chrysalis129 you should consider running clojure with integration in your text editor - it’s a far smoother, richer experience
Hey all, in a philosophical moment I’m interested in a comparison or discussion of Clojure to other lisps/schemes/whatevers. Doesn’t need to be syntax focused, I’m as much interested in things like developer experience, “feeling”, purpose and historical accident results of various languages. Anything, basically. Any content anywhere to recommend? 🙂
One specific thing... what makes Clojure Clojure, as opposed to “almost Common Lisp” (or whatever). What subset of Clojure would be somehow enough to be thought of as Clojure, if at all possible or relevant?
I imagine you may have continued on other channels, but just to give my two cents — I would say the main differences that make Clojure pretty different from something like Common Lisp are that a) clj is much more functional, whereas CL is very multiparadigm; b) clj is hosted (on the JVM, or in the case of cljs, on JS environments); and c) clj uses a wider set of first-class collection data types (ie maps, vectors, sets, lists, as opposed to just lists).
@mattias504 That's probably a discussion better suited to #off-topic or perhaps #other-lisps rather than the #beginners channel (although I understand that beginners may be interested in this topic)
I would seed that discussion with the material here https://clojure.org/about/rationale and here https://clojure.org/about/lisp (the latter is very short tho') -- most of the left-hand links in that "About" section are worth reading as background to your question and provide quite a bit of insight toward answers for it.
There are also some more answers to rationale of differences between Clojure and Common Lisp or Scheme in a talk given by Rich Hickey about 2008 or so, transcript and link to video/audio here: https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/ClojureIntroForLispProgrammers.md
I'll keep an eye on both of those channels for any follow-up discussion -- it's a topic that interests me (and I have some opinions but not really in-depth knowledge of other lisps).