beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
practicalli-john 2020-10-15T00:13:15.419500Z

The Clojure code itself will be the same regardless of if using Leiningen or Clojure CLI tools. The difference is is the details of how you configure Clojure projects and even then there is much cross-over.

zackteo 2020-10-15T05:58:56.420700Z

Hello, could someone explain to me what happens when I do ...

( #(if string?
     (clojure.string/join (reverse %))
     (reverse %)) [:foo :bar :foo])

zackteo 2020-10-15T05:59:15.421200Z

I understand what I want is with do

( #(if string?
     (do clojure.string/join (reverse %))
     (do reverse %)) [:foo :bar :foo])

zackteo 2020-10-15T06:00:28.422700Z

But I would like to just understand the how first ends up going to the true branch to produce ":foo:bar:foo"

dehli 2020-10-15T20:15:42.008500Z

basically string? is a function which is always truthy (which is what your if is evaluating for. in order to invoke it you need to wrap it in () which is why (string? %) behaves like you’d expect (it returns a true of false depending on whether or not % is a string)

michele mendel 2020-10-15T06:03:24.424100Z

This is straightforward

((partial reverse) [3 2 1])
But why does this produce the same result?
((partial reverse [3 2 1]))

zackteo 2020-10-15T06:07:14.426Z

@michelemendel I believe thatt that includes [3 2 1] into reverse to make a new function. So when you call that function it will always execute reverse [3 2 1] - like a function with zero arguments

zackteo 2020-10-15T06:08:19.427100Z

in the first case, (partial reverse) produces a new function that literally does the same thing as reverse (since you don't add in anymore arguments

michele mendel 2020-10-15T06:09:54.428500Z

So in the second case, the reverse has already been done when it reaches partial?

zackteo 2020-10-15T06:11:03.429200Z

yeap the function you effectively produce is kinda like

(fn []
     reverse [3 2 1])

michele mendel 2020-10-15T06:11:53.429700Z

Yes, because this actually works

(partial 3) ;=> 3

mavbozo 2020-10-15T06:15:00.430Z

maybe you want this in the first code

(#(if (string? %)
    (clojure.string/join (reverse %))
    (reverse %)) [:foo :bar :foo])

zackteo 2020-10-15T06:15:40.430900Z

Not sure when you would use that but is a similar idea to (partial +) which produces the + function again I guess

mavbozo 2020-10-15T06:15:55.431Z

as for the first version, everything in clojure is true except nil or false

zackteo 2020-10-15T06:16:29.431200Z

what's the part that get evaluated as true there

mavbozo 2020-10-15T06:16:35.431400Z

(if string? true false) => true

mavbozo 2020-10-15T06:16:48.431600Z

string? is considered as true

zackteo 2020-10-15T06:17:02.431800Z

omg

zackteo 2020-10-15T06:17:04.432Z

thanks ><

mavbozo 2020-10-15T06:17:17.432200Z

it's called nil-punning

zackteo 2020-10-15T06:18:00.433Z

wait i heard that before but could you summarise what that is exactly ?

zackteo 2020-10-15T06:18:27.433300Z

like that all values other than nil and false are true?

mavbozo 2020-10-15T06:18:42.433500Z

yes, that's what I understand

zackteo 2020-10-15T06:19:09.434Z

so this is a case of nil-punning? - > string? is considered as `true`

michele mendel 2020-10-15T06:20:23.435100Z

I think this to make it possible to combine it.

zackteo 2020-10-15T06:20:59.435700Z

But yes thanks 😄

michele mendel 2020-10-15T06:21:05.436100Z

This is where some understanding of category theory is useful.

zackteo 2020-10-15T06:21:32.436600Z

hmmm, i guess edge cases and combining of higher order functions perhaps 😮

mavbozo 2020-10-15T06:21:58.437Z

on second thoughts, i'm not sure your case string? can be considered as nil-punning`

michele mendel 2020-10-15T06:22:18.437400Z

Yes, so in these cases, it look strange taken at face value

mavbozo 2020-10-15T06:22:24.437500Z

your string? case just shows the truthiness concept in clojure

zackteo 2020-10-15T06:23:14.437700Z

okay! let me read up on it

mavbozo 2020-10-15T06:27:29.438Z

do here executes the expressions inside one-by-one then returns the result of the last expression.

mavbozo 2020-10-15T06:28:15.438200Z

so, (do clojure.string/join (reverse %)) executes clojure.string/join then executes and return the value from`(reverse %)`

Jim Newton 2020-10-15T06:33:48.439200Z

cans someone remind how to force a lazy sequence to be non-lazy. It is really difficult to debug a (for ...) loop with too many lazy sequences.

mavbozo 2020-10-15T06:38:57.439300Z

in second case, your ((partial reverse [3 2 1])) becomes

((fn []
   ([] (reverse [3 2 1]))
   ([x] (reverse [3 2 1] x))
   ([x y] (reverse [3 2 1] x y))
   ([x y z] (reverse [3 2 1] x y z))
   ([x y z &amp; args] (apply reverse [3 2 1] x y z args))))

mavbozo 2020-10-15T06:39:21.439600Z

there's 0 arg there so, (reverse [3 2 1) executed

Cameron 2020-10-15T06:39:23.439800Z

doall

✔️ 2
michele mendel 2020-10-15T06:41:06.439900Z

I see. This is from the definition of partial, right?

mavbozo 2020-10-15T06:41:23.440100Z

yes, that's from partial source code

Jim Newton 2020-10-15T06:56:53.440500Z

its not clear from the documentation whether doall returns the sequence.

elarouss 2020-10-15T08:31:40.442900Z

Hello, how can i set the value of a static field in an abstract java class? i want to set the api key for Stripe: Stripe.apiKey = "…"

2020-10-15T08:42:56.443Z

`(set! (. Classname-symbol staticFieldName-symbol) expr)` https://clojure.org/reference/java_interop#_alternative_macro_syntax

Jim Newton 2020-10-15T08:51:30.446100Z

Is there an equivalent of Common Lisp maplisthttp://www.lispworks.com/documentation/HyperSpec/Body/f_mapc_.htm`mapcon` in clojure? I.e., maping functions which iterate over cons cells rather than the contents of cons cells? this is very useful when you need to compute something based on an element but also based on elements you'll see later. E.g. checking whether a list is in order, or removing successive duplicates, or checking the list of vertices of a polygon to detect right turns vs left turns. Unfortunately the function only make sense for lists, not for generalized sequences.

Jim Newton 2020-10-15T08:54:42.448100Z

The reason I need such a function now is I want to scan a list with a given binary predicate to determine whether any two consecutive elements of the sequence satisfy the predicate. E.g., given (1 2 3 4 16 5 6 7) find two concecutive elements (a,b) such that b = a^2 , and if so replace (4 16) with some new merged value computed by a given function.

elarouss 2020-10-15T08:57:10.448400Z

thank you, it worked 🙏

2020-10-15T09:01:00.448900Z

you can craft such function youself

(defn foo [f xs]
  (let [xs' (partition 2 1 xs)]
    (map (fn [pair]
           (f pair))
         xs')))

2020-10-15T09:03:33.449Z

there is also a builder for stripe’s request with method setApiKey might be a little bit more idiomatic solution

Jim Newton 2020-10-15T09:05:06.449200Z

yes in lisp it is pretty easy to write such special purpose functions. but in Common Lisp these function are as friendly as mapcar (CL version of map) which take multiple arity functions such as (map f l1 l2 l3 l4) which expects f to be 4-ary simply because i've given 4 arglists. BTW this is a cool feature of clojure which is pretty difficult to do in Scala.

Jim Newton 2020-10-15T09:06:52.449500Z

For the case in point, I need to remove duplicate elements from a list. but not all duplicates, just the ones of a special form. I.e., duplicate elements x such that (f x) is true for some given f

Jim Newton 2020-10-15T09:08:44.449700Z

the second case is I need to replace a succession of (a b) with either a or b or leave it as (a b) depending on another predicate function. This is part of a symbolic algebraic reduction phase.

Jim Newton 2020-10-15T09:09:42.449900Z

in CL I'd use this cons cell iterator, and in each case look at the first and second elements of the list. and emmit (in a mapcat fashion the elements of the resulting list.

Jim Newton 2020-10-15T09:18:09.450100Z

I can understand why these functions might not be in clojure, because they are very list specific, they don't apply to other non-list sequences.

Jim Newton 2020-10-15T09:35:31.450700Z

but you're right that in lisp you can very often write the function you need as if it were built into the language.

Jim Newton 2020-10-15T11:30:20.459300Z

is thrown supposed to work screwy like this? The compiler claims thrown? cannot be used within (not ...)

(deftest t-invalid-type
  (testing "for invalid type within rte"
    (with-compile-env ()
      (is (thrown? Exception (canonicalize-pattern '(not (:or String Number)))) "test 0")
      (is (thrown? Exception (canonicalize-pattern '(not (or String Number)
                                                         (or Long Number)))) "test 1")
      (is (thrown? Exception (canonicalize-pattern '(and (:or String Number)
                                                         (:or :sigma)))) "test 2")
      (is (thrown? Exception (canonicalize-pattern '(or (:and String Number)))) "test 3")
      (is (not (thrown? Exception (canonicalize-pattern '(:or :epsilon (:cat Integer (:* Integer))))))
          "test 4")
)))

2020-10-15T11:34:07.459500Z

thrown? is not a “normal” function it is a form of assert-expr https://github.com/clojure/clojure/blob/28efe345d5e995dc152a0286fb0be81443a0d9ac/src/clj/clojure/test.clj#L504-L516 and it is trivial to create custom not-thrown? extension as a method of assert-expr

2020-10-15T11:37:11.460Z

(defmethod clojure.test/assert-expr 'not-thrown? [msg form]
  ;; (is (not-thrown? c expr))
  ;; Asserts that evaluating expr not throws an exception of class c.
  (let [klass (second form)
        body (nthnext form 2)]
    `(try ~@body
          (do-report {:type :pass, :message ~msg,
                      :expected '~form, :actual nil})
          (catch ~klass e#
            (do-report {:type :fail, :message ~msg,
                        :expected '~form, :actual e#})
            e#))))
didn’t test it though

Jim Newton 2020-10-15T12:07:28.462100Z

Is there a way to use a simply 2-thread model to evaluate an expression, or call a 0-ary function, and return its return value, however, in a second thread, wait some timeout, and print a message that the expression is taking a long time. I.e., if expr1 takes more than 10 seconds to finish, print a message, and when it finally finishes print a second message indicating the total time.... If the expression finishes before the timeout, then the 2nd thread should print nothing, but should be killed, as I intend to launch 1000s of these in succession.

Jim Newton 2020-10-15T12:10:43.463600Z

I'm generating this as randomized input to some functions during testing. occasionally some test take a long long long time. I'd like to recognize this and find the kind of input which causes it to never return. I can't really use a simple timer, because if it never finishes, the simple timer method wont really work.

Jim Newton 2020-10-15T12:15:07.463800Z

is that the normal way I'm supposed to test whether a certain condition is not thrown?

Jim Newton 2020-10-15T12:16:10.464100Z

I suggested some time ago that clojure test needs an is-not which is like is but logically reverses the expectation.

2020-10-15T12:16:11.464300Z

ask around, i’m not claiming this to be “normal” way)

Jim Newton 2020-10-15T12:17:11.464500Z

thus. (is-not (thrown? Exception....) and (is-not (my-own-predicate ...))

Jim Newton 2020-10-15T12:18:19.464700Z

It could be that I know enough clojure now to implement is-not and submit it as a patch.

2020-10-15T12:19:04.464900Z

ask core members about it first. unlikely this patch will be accepted

2020-10-15T12:20:14.465100Z

clojure.test tend to be as small and simple as possible. is-not looks like syntactic sugar for me

2020-10-15T12:21:41.465300Z

can be implemented outside of framework

(defmacro is-not [form]
  `(is (not ~form)))

alexmiller 2020-10-15T12:50:43.468600Z

You’re making this too hard. You don’t need to assert not thrown at all (an uncaught throw will fail the test). Either just invoke, or assert the return.

Ben Sless 2020-10-15T12:50:59.468800Z

To remove duplicates by predicate you can write something like:

(defn distinct-by
  ([f]
   (fn [rf]
     (let [seen (volatile! #{})]
       (fn
         ([] (rf))
         ([result] (rf result))
         ([result input]
          (let [k (f input)]
            (if (contains? @seen k)
              result
              (do (vswap! seen conj k)
                  (rf result input)))))))))
  ([f coll]
   (sequence (distinct-by f) coll)))

(distinct-by #(mod % 3) [1 5 3 4 2 6])
Which is just a modified version of distinct

Ben Sless 2020-10-15T12:53:05.469Z

to map over pairs of the original sequence, perhaps a transducer will lend itself well

Ben Sless 2020-10-15T12:53:28.469200Z

(transduce
 (comp
  (partition-all 2)
  (map select-a-or-b))
 conj
 []
 xs)

Ben Sless 2020-10-15T12:55:12.469400Z

The CL implementation is very tied to the cons cell abstraction, but Clojure is more generic sequence oriented and has a very large collection of sequence manipulation functions which compose well

1
Ben Sless 2020-10-15T13:01:03.469600Z

(deref (future (expr ,,,)) timout-ms timeout-val)

Ben Sless 2020-10-15T13:03:05.469800Z

For example,

(deref (future (Thread/sleep 1000) (println 'finished)) 100 :timouet)
will return after 100 ms and print finished after 1000 ms

Jim Newton 2020-10-15T13:46:20.470300Z

I believe if you have an uncaught exception the test flow will stop.

Jim Newton 2020-10-15T13:47:10.470500Z

right?

alexmiller 2020-10-15T13:47:52.470800Z

Yes

alexmiller 2020-10-15T13:48:41.471600Z

If you don’t want that, break it into a separate deftest

Jim Newton 2020-10-15T13:49:40.471800Z

there seems to be a piece missing from the testing flow. an is-not test or a not-thrown predicate. yes its not the end of the world if the testing flow fails, just not very elegant.

Jim Newton 2020-10-15T13:53:18.472Z

hmm. not sure how to make this do what I need. I don't want anything printed if it took less than the threshold to run. Maybe I'm thinking about it wrong. But if I tried to do it, I'd have 2 threads. #1 runs the client function #2 sleeps until the timeout If #1 finishes it kills #2, so I don't get 1000s of sleeps in parallel, plugging up the available threads If #2 finishes, then it prints a message, and waits for #1 to finish (if ever), then reports the total time.

2020-10-15T13:55:21.472700Z

how you define “flow”?

(deftest flow
  (testing "flow"
    (is (do (prn "1") (= 1 1)))
    (is (throw (ex-info "exception" {})))
    (is (do (prn "2") (= 2 2)))))
like this ^? if so then in case of unhandled exception it will not stop.

Jim Newton 2020-10-15T13:56:43.474400Z

would it be possible (from the clojure implementation perspective) to re-engineer the memoize function so that when the java heap starts filling up, the cache gets flushed. Of course permission to do so would need to be an option in the call to memoize . When I run huge numbers of randomly generated test cases the java heap fills up on what seems to be simple computation. I suspect it is the fact that several of my functions are memoized.

2020-10-15T13:57:01.474500Z

I think your snippet can be rewritten like this:

(deftest t-invalid-type
  (testing "for invalid type within rte"
    (with-compile-env ()
      (is (thrown? Exception (canonicalize-pattern '(not (:or String Number)))) "test 0")
      (is (thrown? Exception (canonicalize-pattern '(not (or String Number) (or Long Number)))) "test 1")
      (is (thrown? Exception (canonicalize-pattern '(and (:or String Number) (:or :sigma)))) "test 2")
      (is (thrown? Exception (canonicalize-pattern '(or (:and String Number)))) "test 3")
      (is (canonicalize-pattern '(:or :epsilon (:cat Integer (:* Integer)))) "test 4"))))
so “test 4” will fail if exception thrown

2020-10-15T13:58:06.474800Z

and it will be much more elegant if you add assertion into it (is (= some-data (canonicalize-pattern …

2020-10-15T14:04:17.476200Z

I can recommend read throw this chapter — https://www.braveclojure.com/core-async/

alexmiller 2020-10-15T14:04:35.476600Z

it is technically possible using the weaker java ref types (in fact, the interned keyword cache in Clojure is similar). hard to say whether that's a change we would make in core

alexmiller 2020-10-15T14:05:13.477200Z

the diversity of options is why the core.memoize lib exists

Jim Newton 2020-10-15T15:02:51.478500Z

@alexmiller, what's the idea with the core.memoize library. Does it mean I'll have to implement a caching algorithm for my application, or does it mean I can chose from an existing one?

alexmiller 2020-10-15T15:08:09.478700Z

the latter

William Skinner 2020-10-15T16:00:53.480700Z

I'm looking for a critique of my implemenation. It's the basic procedure for a script I'm writing and does a lot of impure/stateful stuff. Would you write it different?

(defn process-oldest-unprocessed [{integration-id :integration/id pattern :integration/file_pattern ftp-info :integration/sftp-info}]
  "Find oldest unprocessed file on sftp for integration.  Copy it to Minio.  Create entry in stage_candidates table."
  (let [processed (-&gt;&gt; (db/all-candidates integration-id) (map :stage_candidate/file_name))]
    (sftp/with-sftp-channel ftp-info
                            (fn [channel]
                              (let [sftp-file-info (sftp/oldest-matching-excluding channel pattern processed)]
                                (minio/create (sftp/get-input-stream channel sftp-file-info))
                                (db/create-candidate sftp-file-info))))))

ghadi 2020-10-15T16:11:42.485700Z

@skinner89 just off the top 1) db/create-candidate doesn't take a db argument - are you using some sort of global state for db? make it explicit, you'll thank me later 2) docstring indicates this should be three separate routines, with a fourth to orchestrate together. Is this the orchestration function? 3) what happens when either copy or db create don't work? 4) what does this function return? consider some sort of explicit record of what happened minor: put the argslist on the next line destructuring is verbose, making needless extra names, leads to cognitive overhead. Consider {:integration/keys [id file_pattern sftp-info]}. Don't worry about the - vs _ idioms. More important to have fewer names.

2020-10-15T16:20:06.486100Z

pretty sure that docstring is in the wrong place too

ghadi 2020-10-15T16:23:42.486400Z

ah yes ^

ghadi 2020-10-15T16:24:05.486900Z

(defn name "docstring" [arglist ...] .....

borkdude 2020-10-15T16:25:13.487700Z

;)

❤️ 2
💕 3
William Skinner 2020-10-15T16:28:20.489Z

Thanks! Hadn't considered the db arg @ghadi.

William Skinner 2020-10-15T16:29:27.489500Z

To answer 3) I would need to cleanup the minio work if db/create fails.

J Crick 2020-10-15T18:35:34.494300Z

I've tried looking online, and did a quick search in this forum, but didn't find an answer. I'm trying to find a learning path to proficiency in modern, idiomatic, production Clojure--something that will tell me what I should learn (in what order, too?), so that I can have a solid sense of direction for my learning (I know that might be complex, as I'm guessing the field is huge, and there are a lot of paths---maybe that's why this doesn't exist, though I've seen things like this for Front End dev). I know about Brave Clojure, and a few other online resources that cover the basics of the language, but, naturally, there's so much more. http://Purelyfunctional.tv is great, but there doesn't seem to be any rhyme or reason to what's there. It feels like a big jumble of videos. I find myself getting stuck because I'm lacking direction. Does anyone here have recommendations for a learning path (or can they point me to something they know that already exists)?

ryan echternacht 2020-10-15T18:40:09.495600Z

Welcome to learning clojure! Unfortunately, I think you're experience is a common one. For my own learning, I found a thing I wanted to build, then figured out how to build it, piece by piece. That got me enough skill to land a job in clojure, and that gave me the support to keep going

ryan echternacht 2020-10-15T18:42:39.498400Z

For me, I focused on building an API first, while building the site in something i knew (Vue). Most of what I needed was just familiarity with writing functional code and clojure idioms, and you should be able to learn this no matter what thing you're working on

ryan echternacht 2020-10-15T18:43:13.499Z

Hope that helps and YMMV. Best of luck! And I've found this community (and this message board specifically) to be quite helpful

dharrigan 2020-10-15T18:59:01.499100Z

How about https://practicalli.github.io/clojure/

dharrigan 2020-10-15T18:59:14.499300Z

https://practicalli.github.io/

dharrigan 2020-10-15T18:59:19.499500Z

two examples

dharrigan 2020-10-15T18:59:51.499700Z

John (who runs Practicalli) has a lot of youtube videos up too on the channel

dharrigan 2020-10-15T18:59:56.499900Z

https://www.youtube.com/c/+practicalli

👍 1
phronmophobic 2020-10-15T19:29:28.000100Z

What kind of projects are you interested in? • games • web servers • web ui • graphics • scripting • data processing • networking • procedural music generation • something else?

practicalli-john 2020-10-15T20:09:47.008200Z

@alibris.lumos as Clojure is a general purpose language, there is not a single learning path except for that you make for yourself. Regardless of content used to learn Clojure, the only way you will make sense of things is identifying specific goals to achieve or projects to build. Without this, anyone learning any programming language will most likely end up lost and frustrated. Learning to write good idiomatic code does contribute to writing production code, however, that is just part of the engineering required to write a production quality system (what ever the context of that is). I suggest to anyone learning Clojure (or any general purpose language) to experiment at first and feel comfortable in understanding how to try things out. Getting comfortable using the Clojure REPL will give you a good foundation, along with learning some of the Clojure core functions (http://www.4clojure.com/ is excellent for this). Once you have a goal or a project in mind, you can start asking specific questions in that context and you should feel like you are making progress. If you can, find someone who will mentor you or someone to learn with. Or just ask lots of specific questions here, its what we are here for.

seancorfield 2020-10-15T20:10:08.008300Z

Clojure Applied is a reasonably good book for "modern, idiomatic, production Clojure" (although the author cautions that when they do a next edition, they will place less emphasis on records and keep to plain hash maps a lot more).

William Skinner 2020-10-15T20:54:13.021400Z

Is there an idiom for saving a value in the middle of a thread pipeline during RDD?

seancorfield 2020-10-15T21:08:26.022200Z

(doto tap&gt;) if you are using something that has tap watchers (such as Reveal or REBL or Portal).

seancorfield 2020-10-15T21:09:37.023500Z

Another option would be (as-&gt; v (def saved-value v)) -- one of the few "good" uses of def not at the top-level: this would create a global saved-value containing the value from the pipeline.

seancorfield 2020-10-15T21:10:16.024100Z

I highly recommend https://github.com/vlaaad/reveal/ as an option here. I use it day-in, day-out for all my RDD @skinner89

seancorfield 2020-10-15T21:16:32.024800Z

(and for anyone who wants to try Reveal, there's a #reveal channel if you get stuck or have in-depth questions about it)

2020-10-15T21:18:19.025100Z

This is such a life saver!

alexmiller 2020-10-15T21:21:01.025300Z

planning to add tap-> for this https://clojure.atlassian.net/browse/CLJ-2538

🙌 3
William Skinner 2020-10-15T21:25:13.025800Z

Nice! Thank you

seancorfield 2020-10-15T22:21:12.026200Z

Nice! My vote would be to ignore tap&gt; failure because if you really want to detect that and do something different, you can always do (doto (-&gt; tap&gt; assert)) or similar...

seancorfield 2020-10-15T22:21:43.026400Z

(since most folks are probably using (doto tap&gt;) right now, they're ignoring the result/failure anyway)