beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
walterl 2021-04-28T00:38:57.191Z

Is there something in core like cond-> that threads the expression value through the test(s) too? I.e. I want to do something like this:

(cond->-> (big-operation-maybe-returns-future!)
  future? deref)

walterl 2021-04-28T00:40:58.191900Z

Best alternative I could come up with is:

(let [result (big-operation-maybe-results-future!)
      result (if (future? result) @result result)]
  ;; ...
  )

walterl 2021-04-28T00:42:01.192600Z

could also use cond-> there, but that seems a bit forced

seancorfield 2021-04-28T02:06:29.194100Z

No, but we released a small library at work that has condp-> that does this…

seancorfield 2021-04-28T02:06:57.194300Z

https://github.com/worldsingles/commons

🎉 1
seancorfield 2021-04-28T02:07:46.195300Z

It has condq (a unary version of condp) and condp-> / condp->> to match cond-> / cond->> but thread the expression through the predicate (plus other stuff).

walterl 2021-04-28T02:24:39.195900Z

Thanks @seancorfield!

Eric Ihli 2021-04-28T02:46:16.202100Z

What's the idiomatic way to do the following. I have a huge list of text files I need to process efficiently. Can't keep everything in memory. So I'm going with transducers.

(transduce
  (comp (remove #(.isDirectory %))
        (map slurp)
        (map #(string/split % #"[\n+\?\.]"))
        (map (partial map #(string/split % #" +")))
        (map (partial map (partial map syllabify-word)))
        (map (partial map (partial map (partial map process-syllable)))))
  conj
  (file-seq (io/file "data-directory")))
What's going on is each step of the transduction creates a new level of a nested sequence. I start with a file, split that on newlines, then split each line of each file on spaces, then split each word of each line of each file into syllables... etc... The nesting gets confusing to reason about, hard to code complicated transformations for. If I could have everything in memory at one time, I'd just have a flatten step somewhere in there. Is there some simplifying alternative that I'm not seeing? Edit: I may have just seen an obvious answer. I can combine most of those into a process-file function which can flatten and do whatever the heck it wants since it will have at most 1 file in memory at a time. Something like:
(defn process-file
  [text]
  (->> text
       (#(string/split % #"[\n+\?\.]"))
       (mapcat #(string/split % #" +"))
       (mapcat syllabify-word)
       (map process-syllable)))

(transduce
  (comp (remove #(.isDirectory %))
        (map slurp)
        (map process-file))
  conj
  (file-seq (io/file "data-dir")))

👍 2
1
2021-04-28T03:16:17.203700Z

Trying to use luminus web framework. After checking the password against the password that's been hashed in the db with buddy.....how exactly do you tell buddy that the user is now logged in and authenticated?

simongray 2021-04-28T06:51:11.203900Z

I don't use Luminus or buddy, but usually you do this by setting a cookie with a session id.

Prabu Rajan 2021-04-28T08:12:10.209200Z

I have a map of maps and I want to lookup by a value (value of a particular entry in the inner map), assuming the value is unique and return the inner map and its key as a vector. Is there a more optimal solution for this?

(defn get-user-by-email [users email]
  (->> (filter #(= email (::email (last %))) (into [] users))
       first))

(get-user-by-email {:one {::first-name "Agatha" ::last-name "Christie" ::email "<mailto:agatha.christie@mail.com|agatha.christie@mail.com>"}
           :two {::first-name "Charles" ::last-name "Dickens" ::email "<mailto:charles.dickens@mail.com|charles.dickens@mail.com>"}}
          "<mailto:charles.dickens@mail.com|charles.dickens@mail.com>")

flowthing 2021-04-28T08:20:07.209500Z

Linear search on a collection usually indicates that you ought to look into making your input data more amenable to lookups. For instance, you could here turn the input map into a map of email -> user:

user=&gt; (def users-by-email
         (into {}
           (map (juxt ::email identity))
           [{::id :one ::first-name "Agatha" ::last-name "Christie" ::email "<mailto:agatha.christie@mail.com|agatha.christie@mail.com>"}
            {::id :two ::first-name "Charles" ::last-name "Dickens" ::email "<mailto:charles.dickens@mail.com|charles.dickens@mail.com>"}]))
#'user/users-by-email
user=&gt; (users-by-email "<mailto:charles.dickens@mail.com|charles.dickens@mail.com>")
#:user{:id :two, :first-name "Charles", :last-name "Dickens", :email "<mailto:charles.dickens@mail.com|charles.dickens@mail.com>"}

flowthing 2021-04-28T08:22:26.209700Z

See also https://stackoverflow.com/a/53692195. But if you absolutely need to do a linear search, using reduce + reduced is probably the fastest option: https://stackoverflow.com/a/32405094

gon 2021-04-28T09:58:46.210200Z

use some

(defn get-user-by-email [users email]
  (some #(and (= email (::email (last %))) %) users))

Prabu Rajan 2021-04-28T15:34:00.211Z

@flowthing Yes, in most cases I want to lookup the user details by user-id, but in some cases I dont know the id and need to lookup by email and hence this

Prabu Rajan 2021-04-28T15:36:18.211200Z

@gon Thanks. I am a bit of a newbie. I am wondering how some works on a map of maps. Does it automatically convert the map into a vector of [:key val] ?

sova-soars-the-sora 2021-04-28T16:15:07.211400Z

Hmm, let's test it in a REPL

sova-soars-the-sora 2021-04-28T16:15:08.211600Z

https://clojuredocs.org/clojure.core/some

Prabu Rajan 2021-04-28T17:37:09.211900Z

Yes, it looks like that. When I did a log of %, I get a vector of the key-value pairs for each entry in the users map. So ‘some’ converts a map of maps into a vector of vectors automatically before applying the predicate

(defn get-user-by-email [users email]
  (some #(-&gt; (log %) (and (= email (::email (last %))) %))
        users))

(get-user-by-email {:one {::first-name "Agatha" ::last-name "Christie" ::email "<mailto:agatha.christie@mail.com|agatha.christie@mail.com>"}
           :two {::first-name "Charles" ::last-name "Dickens" ::email "<mailto:charles.dickens@mail.com|charles.dickens@mail.com>"}}
          "<mailto:charles.dickens@mail.com|charles.dickens@mail.com>")

;;output

[:one #:helloworld.restaurant{:first-name Agatha, :last-name Christie, :email <mailto:agatha.christie@mail.com|agatha.christie@mail.com>}]
[:two #:helloworld.restaurant{:first-name Charles, :last-name Dickens, :email <mailto:charles.dickens@mail.com|charles.dickens@mail.com>}]
=&gt; [:two #:helloworld.restaurant{:first-name "Charles", :last-name "Dickens", :email "<mailto:charles.dickens@mail.com|charles.dickens@mail.com>"}]

Prabu Rajan 2021-04-28T17:38:05.212100Z

Thanks everyone for your help

grazfather 2021-04-28T23:33:16.212800Z

is there just a straight forward way to concat an element to a list?

grazfather 2021-04-28T23:33:28.213200Z

conj adds to the head, I want it on the tail, I don’t care if it’s slow

grazfather 2021-04-28T23:34:18.213700Z

concat '() [element] seems dumb

em 2021-04-28T23:35:16.214Z

is there a reason you can't use a vector?

2021-04-28T23:43:37.214300Z

that syntax is less dumb than what you are doing algorithmically

2021-04-28T23:43:49.214600Z

and yeah, usually a vector is the right answer if you want to add at the end

2021-04-28T23:44:03.214900Z

also - why a list? they are very rarely useful

2021-04-28T23:45:16.215200Z

and concat doesn't return one anyway

user=&gt; (type (concat '(1 2) '(3 4)))
clojure.lang.LazySeq

grazfather 2021-04-28T23:55:21.215400Z

I need it because I am writing a parser

grazfather 2021-04-28T23:55:37.215700Z

that distinguishes lists from vectors

grazfather 2021-04-28T23:56:57.216100Z

I could perhaps build it as a vector and when I see the ) convert it to a list

👍 1
2021-04-28T23:58:49.216700Z

perhaps it distinguishes seqs from vectors? because concat doesn't return a list

2021-04-28T23:59:25.217200Z

and yeah, abstracting the parser internal representation from the concrete clojure data type sounds wise