Fork me on GitHub
#beginners
<
2021-12-09
>
zackteo06:12:51

Hello, what is best way to slurp a file in resources for test? I understand I can do a (slurp (io/resources "dummy.edn")) but my issue is that I'm using lein-modules so depending on where i start the repl, (io/resources "dummy.edn") might not work in the repl. Do I need to use the second arity of io/resources and include a loader ?

seancorfield06:12:59

io/resource lets you read a resource/file from the classpath, so as long as your files are on the classpath, that will work. So the solution is: start your REPL somewhere that has the classpath you need.

seancorfield06:12:37

If you start a REPL in the wrong directory, you will have an incorrect classpath.

zackteo06:12:41

I have a directory/project that is for starting the repl in (like a dev folder), where I load the other modules as source-paths . Is there a way I can do a slurp that doesn't involve using the full path, but still allow me to this code to work in the repl?

emilaasa15:12:07

All the resource files from your classpath will be available. You could try listing the resources available in io/resource and you'll see what's there:

(-> (io/resource ".")
    io/file
    file-seq)

emilaasa15:12:59

If it's something that should work long term/in prod you should figure out the class paths so that the code that uses the file has access to it. If you only need it for a while you can use plain slurp from your own filesystem

emilaasa15:12:05

with an absolute path

zackteo02:12:38

That didn't really list out the resources but it did help me find out what's my classpath

zackteo07:12:28

Is there a way I can include more directories in the class path? Or change the classpath of the repl? Am trying to think of the best ways to work around this, given how my project is set up

zackteo03:12:55

apparently i can using cemerick.pomegranate/add-classpath

V09:12:05

I have a scenario where i want to fetch a value, which is updated outside of the system itself. If this value is "In-progress" i will need to repeat fetching and checking the value until the value has changed to another status, maybe even with some delay. Is there a common way to approach this problem in clojure?

cddr12:12:57

@U01GQRC8W30 It probably depends on what you want to do with the value once you've fetched it. You could use a promise so that the caller can block until the fetch returns a non "in-progress" value by using deref on the returned promise

(let [p (promise)]
    (future
      (loop []
        (let [v (fetch-value)]
          (if-not (= v "in-progress")
            (deliver p v)
            (recur)))))
    p))
Alternatively, if you don't want the caller to be blocked, the fetch function could be passed a callback to run on the fetched value once it returns a non "in-progress" value.
(defn fetch-and-doit [doit-fn]
  (future
    (loop []
      (let [v (fetch-value)]
        (if-not (= v "in-progress")
           (doit-fn v)
           (recur)))))

🙏 1
🙌 1
cddr12:12:59

There's also libraries which help with this sort of thing. I like https://github.com/mpenet/auspex

emilaasa14:12:51

I'd like to add a docstring to a memoized function, presenting the appropriate times to use it vs the non memoized version. If I only do: (def f-mem (memoize f)) then there's no docstring. If I do: (defn f-mem "docstring" [] (memoize f)) there's a docstring but not the correct argument list Is there a nice way to do this?

pavlosmelissinos14:12:02

(def f-mem "docstring" (memoize f)) ?

delaguardo14:12:37

(def ^{:doc (-> #'f meta :doc)} f-mem
  (memoize f))

👍 1
delaguardo14:12:56

docstring is just a metadata attached to the var

pavlosmelissinos15:12:17

I thought you wanted a different docstring for the memoized version but yeah if you want to reuse the one of the original function you have to do what @U04V4KLKC suggested. Btw, in your defn example, f-mem is a 0-arity function, so you have to call it in order to get the memoized version of f, that's why (f-mem x) doesn't work but ((f-mem) x) does. (memoization won't work with the latter though - you'll get a different memoized function every time you call it)

indy15:12:16

Adding to what has already been suggested, if you want to annotate the arglist of the memoized version you can add the arglists metadata

^{:arglists '([arg1 arg2])}

emilaasa15:12:09

Ah interesting, I'm giving it a shot! due to the length of the comment I also tried the with-meta , and when I looked at the source code I eventually went with that style of metadata:

(def
 ^{:arglists '([^clojure.lang.IObj obj m])
   :doc "Returns an object of the same type and value as obj, with
    map m as its metadata."
   :added "1.0"
   :static true}
 with-meta (fn ^:static with-meta [^clojure.lang.IObj x m]
             (. x (withMeta m))))

emilaasa15:12:05

A always, much thanks to you all 🙂

hiredman17:12:03

def'ing a memoized function is often a bad idea

hiredman17:12:53

memoize doesn't provide any control over what it saves, and that just grows and grows, and a def is a global

👍 1
🙏 1
Sam Ritchie21:12:49

Mandatory plug for https://github.com/clojure/core.memoize if you do need to do this

emilaasa21:12:50

Thanks I'll think about this an extra time 🙂

maverick17:12:48

How can I add lazyseq of maps from database into #{} ?

dpsutton17:12:33

a set of maps sounds kinda strange to me. But presumably you can just do (into #{} coll) and have the result you want

maverick18:12:33

I want to only add a particular key value into #{}.

dpsutton18:12:46

can you type out some representative data?

maverick18:12:57

data in form of lazyseq is [{:key1 "value1" :key2 "value2"} {:key1 "value3" :key2 "value4}] I want to do into #{} only key1 values

maverick18:12:51

I am trying to do (into #{} (mapcat #(get % :key1) data))

maverick18:12:59

But it is not working

dpsutton18:12:06

(into #{} (map :key) coll)

dpsutton18:12:51

(into #{} (map :key1) [{:key1 "value1" :key2 "value2"} {:key1 "value3" :key2 "value4"}])
#{"value1" "value3"}

maverick10:12:41

THis is not working

mathpunk21:12:32

Is there a common idiom for: you've got a map shape and a function foo that processes it, but you want to use the same function name for a collection of those maps?

mathpunk21:12:41

I was thinking multimethod

mathpunk21:12:56

but map is a coll? so that's not the predicate

phronmophobic21:12:19

you typically don't create functions that operate on a collection of the same item since it's usually the same number of characters and less general than (map foo my-maps)

mathpunk21:12:37

yeah, that's a good argument

mathpunk21:12:44

i was trying to avoid keeping track of when i had a single or a collection but, i guess that's a programmer job not a computer job

phronmophobic21:12:57

yea, that's a tempting pattern, but I've found that it usually just leads to unnecessary complexity and hard to find bugs

phronmophobic21:12:08

it's the same trap that you end up in any time you think you want to use flatten

seancorfield23:12:10

(and I think he has one about "heisenparameters" which covers the case of a parameter which might be a collection or not...)

seancorfield23:12:41

Oh, haha, yeah, he even links to it in the first line of the redundant map post! https://stuartsierra.com/2015/06/10/clojure-donts-heisenparameter