clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
borkdude 2021-03-14T10:33:21.097200Z

@meditans This tools is based on clj-kondo's output: https://github.com/benedekfazekas/morpheus

william 2021-03-14T12:02:06.097800Z

thanks @borkdude!

2021-03-14T18:54:48.100400Z

i wasn't able to find anything on this -- how would i go about defining my own custom global vars, such as *assert* ? let's say i want to introduce a *my-assert* that's either set to true or false at compile time (configurable through lein), what would be the way?

2021-03-14T18:56:55.101200Z

i know i can probably use java system properties, but i was aiming for an approach that's portable between clj and cljs

2021-03-14T18:59:44.101400Z

@lmergen

2021-03-14T19:00:04.101900Z

(def ^:dynamic *my-thing*)

2021-03-14T19:00:36.102500Z

but can i then easily toggle *my-thing* through compile-time flags ?

2021-03-14T19:01:18.103300Z

i'll want something like

:global-vars {*my-thing* false}
in profiles, in this specific case to enable/disable some instrumentation

2021-03-14T19:05:15.103900Z

Something like

:injections [(set! my-thing)]

2021-03-14T19:05:31.104200Z

:thinking_face: ok that works indeed

vemv 2021-03-14T19:36:27.106300Z

Leiningen also offers :global-vars precisely for that IMO neither :injections or :global-vars are clean solutions because they don't transparently translate to an official Clojure feature so instead I'd compile (or run) my code while explicitly binding the given var

borkdude 2021-03-14T19:50:39.106800Z

@lmergen Not portable, but CLJS offers goog-define for this. I bet you can make it portable using some .cljc though

2021-03-14T19:51:19.107300Z

yeah I think I’ll do something like that

2021-03-14T21:10:11.110800Z

how do you explicitly bind your var at compile time though? do you use a compiler option of some sort? let’s say I want to turn on/off some instrumentation that affects defn definitions, how would you approach this without any compiler flags?

vemv 2021-03-14T21:57:15.111Z

let's say that you're app's main ns is called <http://my.app|my.app> I'd create a ns called my.main. It would look like the following:

(ns my.main
  ;; important! no requires here
  )

(defn -main [&amp; _]
  (binding [*assert* false]
    (require '<http://my.app|my.app>) ;; compile `<http://my.app|my.app>` with a specific binding
    ))
This way my.main would be the entrypoint in production. The technique works with AOT too

mauricio.szabo 2021-03-14T22:05:48.111600Z

Sure enough, if I can make this work for Chlorine, it'll work for Clover too. I was trying to figure out why someone would want to use the "Inferior REPL mode", but now I have an example 😄

lilactown 2021-03-14T22:23:39.112300Z

I'm trying to figure out when the appropriate time is to use a transducer's single arity

ghadi 2021-03-14T22:28:46.117100Z

the completion arity?

lilactown 2021-03-14T22:29:09.117800Z

I'm making a thing that is sort of like a stream. it has an "input" function which sets up listeners to other streams and returns the next value, and I want to accept a transducer to transform that. e.g.:

(stream (remove even?) #(inc @counter))
when the stream is initialized, it needs to run the input function and set its initial value. however, if e.g. counter starts at -1, then (remove even?) should reject it
(even? 0)
;; =&gt; true
but right now, when the stream doesn't have a value yet, I thought I should use the single-arity of the transducer. but that simply passes the first value to the reducer :thinking_face: meaning that the first value of the stream is 0

lilactown 2021-03-14T22:29:32.118100Z

ah, it's meant for completion?

ghadi 2021-03-14T22:30:31.119400Z

[] [x] [x input] which arity do you mean?

lilactown 2021-03-14T22:30:36.119600Z

[x]

lilactown 2021-03-14T22:30:48.119900Z

1-arity

ghadi 2021-03-14T22:33:12.122Z

that's the completion arity

(transduce
  (map inc)
  (fn
    ([sb] (.toString sb))
    ([sb input] (doto sb (.append (str input)))))
  (StringBuilder.)
  [1 2 3 4 5])

ghadi 2021-03-14T22:33:50.122400Z

example is illustrative, it has reflective calls

ghadi 2021-03-14T22:34:27.122600Z

user=&gt; (transduce (map inc) (completing conj! persistent!) (transient []) [1 2 3 4 5])
[2 3 4 5 6]

ghadi 2021-03-14T22:35:57.123900Z

completing is a higher-order function that wraps a completing arity persistent! on an existing reduction function conj!

ghadi 2021-03-14T22:36:44.124400Z

completion arity is useful for finalizing something after the "stepping" process is done

lilactown 2021-03-14T22:37:01.124600Z

I see

lilactown 2021-03-14T22:38:22.125700Z

I guess then perhaps I should follow in the tradition of reduce transduce and allow the consumer to provide an initial value to the stream?

lilactown 2021-03-14T22:38:53.126300Z

(stream (remove even?) #(inc @counter) 1)

ghadi 2021-03-14T22:38:57.126600Z

dunno

ghadi 2021-03-14T22:39:21.127200Z

not all transducible contexts take initial values, nor produce a finalized output. e.g. sequence or chan

seancorfield 2021-03-14T22:51:10.129600Z

With next.jdbc and reducible result sets, there's no obvious initial value because you don't know how the rows are going to be processed. Is the user aggregating numbers? Building a new collection? So users always have to provide their own initial value.