clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
ghadi 2021-04-07T00:00:22.133500Z

it's sad because it puts the chained exception within the ex-data in addition to chaining it as the ex-cause I end up doing everything Alex mentioned minus setStackTrace

ghadi 2021-04-07T00:01:03.134200Z

preserve the chained cause & ex message, but dissoc stuff from the data

ghadi 2021-04-07T00:01:58.136Z

for that case it doesn't matter that the outermost exception's stacktrace differs, the real meat of the stacktrace is on the chained cause

2021-04-07T00:01:59.136100Z

aaah, I was trying to set! the data field (which obviously didn't work), but .setStackTrace might do it. Especially if it's as simple the example @hiredman pasted.

2021-04-07T00:02:49.136900Z

Thank you all very much!

ghadi 2021-04-07T00:03:27.137Z

Michael Lan 2021-04-07T01:18:34.137600Z

Within a REPL session, is it possible to add a new dependency? Using Deps and CLI.

alexmiller 2021-04-07T01:21:16.138600Z

there is an experimental add-libs3 branch in tools.deps.alpha that provides this functionality. we expect it to eventually be included but there are some key integration questions we still have. Sean Corfield's deps.edn has some setup info for this https://github.com/seancorfield/dot-clojure

seancorfield 2021-04-07T01:36:08.139300Z

@michaellan202 There’s an example of how I use add-libs on that branch here https://github.com/seancorfield/next-jdbc/blob/develop/test/next/jdbc/test_fixtures.clj#L229-L244

❤️ 1
seancorfield 2021-04-07T01:37:44.141300Z

That lets me add all of next.jdbc’s test dependencies into a running REPL that was started from another project (that may well depend on next.jdbc, but without those deps). This lets me run next.jdbc’s tests from my editor, even when working on another project.

Michael Lan 2021-04-07T01:38:58.142200Z

Got it, so it’s not a permanent addition, just temporary

seancorfield 2021-04-07T01:39:44.142900Z

It just loads libs into the REPL. If you want them present the next time you start the REPL, you need to add them to deps.edn.

seancorfield 2021-04-07T01:41:09.144400Z

In one of my RDD talks I show how you can edit deps.edn to add dependencies and then call add-libs on that same hash map from within deps.edn (by having some code in deps.edn that is normally commented out).

seancorfield 2021-04-07T01:42:43.145400Z

(I am tempted to automate that so I can just edit deps.edn, put my cursor just inside the :deps map or :extra-deps map, and hit a hot key and have add-libs called on that…)

Michael Lan 2021-04-07T01:44:23.145600Z

haha, that sounds really convenient

seancorfield 2021-04-07T02:03:26.147300Z

Just added it to https://github.com/seancorfield/vscode-clover-setup — you need the :add-libs alias from my dot-clojure repo active when starting a REPL and then you can just edit the :deps or :extra-deps in your deps.edn file and with cursor inside the lib spec hash map, ctrl-; shift+a and it sends it to add-libs and loads those dependencies!

Yehonathan Sharvit 2021-04-07T06:52:02.153500Z

When I have a namespace with a couple of defmethod declarations, what’s the best way to make sure the namespace is loaded (I mean required)? For instance, let’s say I have a library whose main ns is my-lib.core and the defmehtod declarations are in my-lib.foo Should I write something like?

(ns my-lib.core
   (require my-lib.foo))
The problem is that when someone looks at the ns form, my-lib.foo seems superfluous. And in fact cider-refactor removes it as it considers it as a unused libspec vector

flowthing 2021-04-07T06:58:52.155300Z

I'd like to write code that behaves differently depending on the user's Java version. More specifically, I'd like to write a function that uses java.lang.module.ModuleFinder if it's available, and just returns nil if not. Any general pointers on how to approach this? If you can point me to any prior art on this topic, I'd appreciate it.

2021-04-07T07:05:14.155400Z

https://clojure.github.io/clojure/clojure.reflect-api.html You can use resolve-class from that api

flowthing 2021-04-07T07:06:51.155600Z

Thanks! I'll look into that.

jumar 2021-04-07T07:11:27.155800Z

There's also when-class - it's used for conditional loading of java.sql.Timestamp: https://github.com/clojure/clojure/blob/3c9307e27479d450e3f1cdf7903458b83ebf52d7/src/clj/clojure/core.clj#L6796-L6803

flowthing 2021-04-07T07:12:17.156600Z

Thanks! That looks nice and straightforward.

alexmiller 2021-04-07T12:32:47.208600Z

Note that that code doesn’t exist in core anymore

alexmiller 2021-04-07T12:33:15.209200Z

But feel free to borrow it

flowthing 2021-04-07T12:34:48.210600Z

Sure. I borrowed the gist of it, that got me there.

flowthing 2021-04-07T12:38:19.210800Z

https://github.com/eerohele/Tutkain/blob/30578b438d6a57be25c83d24f79de281b79ffbd7/clojure/src/tutkain/repl/runtime/completions.clj#L137-L150 The mapcat fn still reflects, and I'm not sure how to hint it when java.lang.module.ModuleReference is not guaranteed to exist, but it's not really a big deal.

alexmiller 2021-04-07T12:49:31.211600Z

you could use a fn and type hint the argument

alexmiller 2021-04-07T12:49:41.211800Z

oh, you can't do that

flowthing 2021-04-07T12:58:42.212Z

Yeah, that's what I'd like to do.

flowthing 2021-04-07T12:59:58.212200Z

I figured I could maybe use the same kind of type hint as with string arrays etc., but it didn't seem to pan out, or then I just didn't get it right. The "syntax" is a bit fiddly.

alexmiller 2021-04-07T13:09:36.212700Z

I think the compiler is going to lead you into trouble in that case instead

flowthing 2021-04-07T13:13:22.213Z

Yeah.

craftybones 2021-04-07T07:29:35.158100Z

What is the cleanest/most idiomatic way of taking an existing map with plain keywords and turning it into a map with namespace qualified keywords?

{:a 1 :b 2} => {:foo/a 1, :foo/b 2}

craftybones 2021-04-07T07:30:18.158900Z

I am using rename-keys which works, but I am positive there’s a better mechanism for this

craftybones 2021-04-07T07:35:15.159900Z

There was a reduce-kv based solution on stackoverflow which is similar to my rename-keys approach…

simongray 2021-04-07T07:45:27.161800Z

@srijayanth creating a map-vals or map-keys is like an initiation ritual for a Clojure developer since they don’t come with the standard library… 😛 I like to for to iterate through the key-value pairs and then into to create the new map

simongray 2021-04-07T07:45:41.162300Z

(into {} (for [[k v] {:a 1 :b 2}]
           [(keyword 'foo k) v]))

craftybones 2021-04-07T07:46:26.162900Z

thx @simongray

simongray 2021-04-07T07:47:00.163400Z

np. I wrote that piece of code so damn many times

craftybones 2021-04-07T07:47:08.163600Z

fyi, as noob as my question sounds, I’ve been using Clojure since 1.2 😄

simongray 2021-04-07T07:47:13.163800Z

haha

craftybones 2021-04-07T07:47:54.164900Z

I still don’t get why rename-keys is in clojure.set. I remember somebody providing an explanation that seemed adequate at that time

simongray 2021-04-07T07:47:55.165Z

don’t worry, I’ve never even used a transducer… 😛

craftybones 2021-04-07T07:48:21.165500Z

I love transducers. I wrote this simple version of 2048 that uses transducers

simongray 2021-04-07T07:48:54.166300Z

yeah I know they’re great, I just don’t like how it makes my code look and I never had any real performance issues, so I never bothered to use them 😛

simongray 2021-04-07T07:50:43.166900Z

probably should get over it and use transducers everywhere applicable

craftybones 2021-04-07T07:51:27.167300Z

Even without performance issues, they come in handy.

craftybones 2021-04-07T07:51:48.167700Z

It is a lot easier to compose transducers and pass them around

simongray 2021-04-07T07:52:22.168300Z

right… do you have a recommended article or something for me to get into the right mindset?

simongray 2021-04-07T07:53:12.169500Z

I’ve seen them around in codebases I’ve been working on, so I’ve edited them… just never ran into a situation that made me think “that calls for a transducer!”

jumar 2021-04-07T07:53:33.170Z

Btw. for map-vals et al I really like to use medley library. It also has map-keys:

(map-keys #(keyword "foo" (name %)) {:a 1})
;;=> #:foo{:a 1}

craftybones 2021-04-07T07:53:46.170200Z

Thanks @jumar

simongray 2021-04-07T07:54:13.171300Z

@jumar it’s such a tiny bit of code that pulling in a library just seems overkill 😉 but I guess if you use medley for other things, it makes sense

craftybones 2021-04-07T07:55:52.173100Z

@simongray - when transducers came out, I was a little befuddled about how they work. There’s a Rich Hickey talk where he exposes the insides of a transducer(it isn’t the StrangeLoop one I think). After that, every time I see code that has a series of 2 or more map/filter/reduce/iterative constructs, I eagerly convert them to transducers

craftybones 2021-04-07T07:56:54.174300Z

We once had a discussion here about any scenario where a transducer might not be preferred. While someone pointed out something around eagerness/laziness etc, I came away feeling that there’s very few downsides to using transducers at all

craftybones 2021-04-07T07:57:53.175100Z

For instance, here’s the transducer chain for that 2048 bit

(def xform (comp (remove zero?)
                 (partition-by identity)
                 (mapcat #(partition-all 2 %))
                 (map (partial apply +))))

craftybones 2021-04-07T07:58:25.175600Z

And I end up using it as follows

(defn move-left [row]
  (take 4 (concat (sequence xform row) (repeat 0))))

craftybones 2021-04-07T07:58:51.176300Z

If you see the xform, it reads incredibly clearly from top to bottom

craftybones 2021-04-07T07:59:15.176900Z

remove zeroes, partition equal numbers together, chunk them in 2s and sum them up

craftybones 2021-04-07T07:59:51.177400Z

I eventually wrote my own stateful transducer that pads the ends of collection with zeroes. I stuck that transducer to the end of the chain

simongray 2021-04-07T08:00:24.177900Z

thanks a lot

jumar 2021-04-07T08:00:54.178500Z

yeah, I use map-vals , find-first, index-by and assoc-some most frequently. What I like about map-vals in particular is that it has a lot more meaningful name than just using the idiom (although when you get used to it it's also quite readable) - another aspect could be performance but I don't care about that one in most cases.

simongray 2021-04-07T08:00:57.178700Z

I guess I just need to get into the habit of converting most functions that contain a threading macro into composed transducers

craftybones 2021-04-07T08:01:29.179400Z

Yeah, my personal limit is more than 2. if there’s more than 2 maps/filters in sequence, then that’s an ideal candidate for transducers

craftybones 2021-04-07T08:01:40.179700Z

It really is a shame that not enough people use it. I find it awesome

1
craftybones 2021-04-07T08:01:58.180Z

I transduced the hell out of those advent of code problems

jumar 2021-04-07T08:03:09.181500Z

I like this discussion about when to use transducers: https://groups.google.com/forum/#!topic/clojure/JjiYPEMQK4s I think it's very helpful to understand the use cases even without knowing how exactly they work. Especially Alex Miller's points: > I would say transducers are preferable when: • 1) you have reducible collections • 2) you have a lot of pipelined transformations (transducers handle these in one pass with no intermediate data) • 3) the number of elements is "large" (this amplifies the memory and perf savings from #2) • 4) you put to produce a concrete output collection (seqs need an extra step to pour the seq into a collection; transducers can create it directly) • 5) you want a reusable transformation that can be used in multiple contexts (reduction, sequence, core.async, etc) 

👍 1
simongray 2021-04-07T08:04:02.181800Z

thank you!

simongray 2021-04-07T08:04:59.182700Z

I rarely need reusable transformations, but maybe I just haven’t looked hard enough.

simongray 2021-04-07T08:05:20.183200Z

that’s what I mean about the mindset. Gonna scan that thread for some rules of thumb.

simongray 2021-04-07T08:05:39.183500Z

but obviously memory savings is advantageous too

simongray 2021-04-07T08:06:02.184500Z

and @srijayanth is right in that lazy collections are rarely called for in practice

craftybones 2021-04-07T08:06:25.185100Z

They are useful as hell though 🙂

simongray 2021-04-07T08:06:28.185200Z

I can think of maybe 4-5 cases where I actually use lazy (usually infinite) collections

simongray 2021-04-07T08:07:10.185800Z

and I’m pretty sure I only remember them because they are noteworthy for being the rare infite colls

craftybones 2021-04-07T08:07:35.186300Z

I end up using cycle a fair amount. It is sometimes surprising how often that pattern shows up

craftybones 2021-04-07T08:08:07.187100Z

You can make pretty cool spinners with a simple cycle

simongray 2021-04-07T08:08:33.187600Z

yeah, in one case I use cycle to take N items from a randomised colour selection

simongray 2021-04-07T08:08:47.188200Z

to colour some tabs in a CLJS lib I make

simongray 2021-04-07T08:09:16.188800Z

and then iterate is another common case of infinite colls

craftybones 2021-04-07T08:09:31.189200Z

(cycle "|/-\\")
A nice classic spinner 🙂

simongray 2021-04-07T08:09:40.189400Z

hah, nice one

craftybones 2021-04-07T08:10:09.189800Z

the other way is to have different css styles/classes cycled

craftybones 2021-04-07T08:10:42.190300Z

You can also make those annoying prehistoric marquees from the geocities days

simongray 2021-04-07T08:11:58.190800Z

my tabs use case for cycle : https://github.com/kuhumcst/stucco/blob/master/src/dk/cst/stucco/plastic.cljs#L28-L37

Yehonathan Sharvit 2021-04-07T08:34:21.191400Z

It’s because rename-keys is part of relational algebra and the natural way to represent a relational in Clojure is as a set of maps.

nilern 2021-04-07T09:26:48.196600Z

Transducer chains aren't much harder to read than ->> chains so I would also prefer transducers even for not so performance sensitive code Premature optimization is one thing but wasting cycles for no good reason is another Like after Java 8 people realized that it makes no sense to go converting most loops to Streams because you probably lose 20-30% on performance and simple loops read just fine

simongray 2021-04-07T10:24:10.197600Z

@nilern you’re saying premature optimisation is a good thing?? 😛

simongray 2021-04-07T10:24:33.197800Z

anyway, you’re probably right

simongray 2021-04-07T10:25:19.198700Z

I actually thought that Java 8 streams were kinda transducer-like, i.e. they were more performant than regular loops

simongray 2021-04-07T10:26:08.199Z

but obviously it’s not something I ever researched very deeply 😛

simongray 2021-04-07T10:27:14.199500Z

like I seem to remember something something parallelism, laziness, blablabla

Ben Sless 2021-04-07T11:09:12.199700Z

Transducers also usually get you to stop and think for a few seconds, which is always good when programming. How many times did you find in code review someone used flatten when mapcat would have been fine? I often see it pop up when there's some confusion. While worrying about optimization prematurely is silly, so is shooting oneself in the foot from the onset

nilern 2021-04-07T11:56:36.200Z

Yeah flatten is often a red flag and not because it is slow but because is a deep flatten even correct...

restenb 2021-04-07T12:03:35.205Z

so how do you deal with dependency cycles? I have this stateful "core" of what i'm writing at the moment, and an external service living two namespaces away, each depending on the previous. the service then needs to update the state. enter dependency cycle.

nilern 2021-04-07T12:03:41.205300Z

If there is a lot of data you can utilize more cores with .parallel() But in the single-threaded case transducer/Stream pipelines only beat handwritten code if it is too gnarly to do everything in a single handwritten loop so intermediate collections are added

2021-04-07T12:11:05.207500Z

you can extract everything related to state, including functions to update, into separate namespace and then require it from every service and the core.

alexmiller 2021-04-07T12:31:32.207800Z

https://clojure.org/guides/faq#transducers_vs_seqs

Ben Sless 2021-04-07T12:46:15.211200Z

yup, like i said, it's usually a place where mapcat should be used, but somewhere the dev lost control of the return type - I saw it recently with a function which returned a sequence of maps, simplified some things, switched to mapcat and broke a test, because the test mocked the function to return a map instead of a sequence of maps. That function was then mapped on the input sequence, which made flatten work and mapcat not. It always feels good to fix wrong assumptions in tests on top of offensive functions

Ben Sless 2021-04-07T12:47:03.211400Z

whenever I see flatten I read "I'm not sure what's going on here, yolo"

raspasov 2021-04-07T14:16:50.213600Z

What’s better:

(vec
 (map-indexed
  (fn [idx x] [idx x])
  [:a :b :c]))
;or
((comp vec map-indexed) 
 (fn [idx x] [idx x]) 
 [:a :b :c])

raspasov 2021-04-07T14:17:26.213900Z

(assuming I’m not using transducers)

localshred 2021-04-07T14:17:51.214400Z

beauty is in the eye of the beholder 🙂

👌 1
raspasov 2021-04-07T14:17:52.214500Z

Goal is to have a vector at the end.

raspasov 2021-04-07T14:19:01.214600Z

Personally, if there’s more than one transformation happening, I switch to transducers.

☝️ 1
nilern 2021-04-07T14:21:20.215700Z

In that case comp is just pointless obfuscation

🆗 1
2021-04-07T14:21:29.216200Z

Imo probably the first one, but there's also

(into []
  (map-indexed (fn [idx x] [idx x]))
  [:a :b :c])
(I'd still probably default to just wrapping the map-indexed call with vec)

👌 2
p-himik 2021-04-07T14:21:51.216800Z

user=> (reduce-kv (fn [acc i v] (conj acc [i v])) [] [:a :b :c])
[[0 :a] [1 :b] [2 :c]]

p-himik 2021-04-07T14:22:01.217200Z

Vectors are associative collections from an index to a value.

raspasov 2021-04-07T14:22:51.218Z

Do you prefer that over all other options, in terms of readability or even shortness? Or you’re just showing other options 🙂

nilern 2021-04-07T14:23:12.218200Z

(into [] (map-indexed vector) [:a :b :c])

raspasov 2021-04-07T14:23:14.218300Z

Or is this faster? (I haven’t done benchmarks on reduce-kv)

p-himik 2021-04-07T14:23:58.219400Z

In terms of readability, I would not think about it at all and just extract it into a well-named function. :)

👌 1
nilern 2021-04-07T14:24:25.220Z

A map result could also be handy (zipmap (range) [:a :b :c])

p-himik 2021-04-07T14:24:38.220100Z

This gives a wrong result though. Ah, the edit. :)

nilern 2021-04-07T14:25:02.220500Z

Sorry about that

raspasov 2021-04-07T14:26:05.220800Z

I’m looking for the neatest code for an indexed vector for React components; map is no-go there.

raspasov 2021-04-07T14:26:25.221Z

Needs order.

nilern 2021-04-07T14:26:37.221200Z

If you really want to optimize (persistent! (reduce-kv (fn [acc i v] (conj! acc [i v])) (transient []) [:a :b :c]))

raspasov 2021-04-07T14:26:52.221400Z

And idx accessible on each one.

nilern 2021-04-07T14:27:16.221600Z

In that case, not handy

p-himik 2021-04-07T14:27:40.221800Z

into does exactly that. :)

nilern 2021-04-07T14:29:49.222Z

It uses normal reduce but yeah

raspasov 2021-04-07T14:30:12.222200Z

In any case, thanks for the input!

nilern 2021-04-07T14:30:30.222400Z

If the goal was to produce a map then reduce-kv can avoid allocating those kv pairs

👍 1
craftybones 2021-04-07T16:11:05.224200Z

(mapv vector (range) [:a :b :c])

craftybones 2021-04-07T16:12:59.225Z

But beware that mapv is eager

grazfather 2021-04-07T16:13:46.225200Z

How has this not been posted? https://clojure.org/news/2021/04/06/state-of-clojure-2021

alexmiller 2021-04-07T16:14:12.225900Z

It was in #announcements yesterday

craftybones 2021-04-07T16:15:13.226800Z

Fogus wrote this one. I am going to read tea leaves and say that Alex was busy getting spec 2 ready. Sometime this week? 😉

🙏 3
borkdude 2021-04-07T16:16:21.227600Z

Thanks for publishing the survey and the write-up @fogus!

craftybones 2021-04-07T16:19:09.228500Z

Urgh:

user=> (keyword "emp.id" (str 100))
:<http://emp.id/100|emp.id/100>
user=&gt; :<http://emp.id/100|emp.id/100>
Syntax error reading source at (REPL:2:0).
Invalid token: :<http://emp.id/100|emp.id/100>

craftybones 2021-04-07T16:21:08.230200Z

I can obviously write a fn to normalise this, but is there any real way to deal with numeric keys?

Timur Latypoff 2021-04-07T16:21:30.230400Z

I remember someone from the Clojure team was saying that keywords should not start with a digit (like symbols), but the ability to construct them has been retained for backward compatibility.

craftybones 2021-04-07T16:21:57.230600Z

The problem I have is that I am receiving a json that I am then namespacing

craftybones 2021-04-07T16:22:09.230800Z

As I said, I can always use a fn to prefix something

2021-04-07T16:22:36.231Z

just don't

Timur Latypoff 2021-04-07T16:22:40.231200Z

You can use non-keyword keys (string or integer keys) just fine, if that works for you @srijayanth

craftybones 2021-04-07T16:23:15.231400Z

yes, I’ll just add a prefix

craftybones 2021-04-07T16:25:29.231600Z

Thanks

grazfather 2021-04-07T16:32:16.231900Z

Ah!

Michael Gardner 2021-04-07T18:04:28.235Z

I seem to recall Rich saying that he might've used transducers as the basic abstraction for Clojure's collection APIs instead of seqs, if he'd thought of them back then. Am I remembering correctly? I'm very curious what that would look like, if so.

nilern 2021-04-07T18:19:45.235200Z

Sounds strange. Sometimes you really need first and rest -- https://www.metosin.fi/blog/malli-regex-schemas/ comes to mind.

nilern 2021-04-07T18:31:58.235600Z

Parsing style usage is an extreme case but stopping processing early or processing multiple collections gets awkward. There are solutions like reduced or various flatmapping and zipping operations but even if the little extra allocations go away after inlining the pipeline abstraction stops being a friend at some point. I have used a lot of https://odis-labs.github.io/streaming/streaming/Streaming/Stream/index.html in OCaml but Java 8+ Streams seem similar.

raspasov 2021-04-07T18:42:47.235800Z

@michael348 Yes I clearly recall this from a talk; I can’t remember which one but that sounds about right;

raspasov 2021-04-07T18:45:09.236Z

@nilern I am not so sure about rest ; perhaps it’s a coding style, but I don’t really use it often in day-to-day code; It does feel pretty low level to me (as in, not something I’d default to);

2021-04-07T18:47:48.236200Z

another option is to write code in terms of a protocol, have a shared protocol namespace, and a separate implementation namespace that most consumers never need to care about

flowthing 2021-04-07T18:48:42.236500Z

From the History of Clojure paper: > I think transducers are a fundamental primitive that decouples critical logic from list/sequence processing and construction, and if I had Clojure to do all over I would put them at the bottom.

nilern 2021-04-07T18:49:16.236700Z

Already in my PHP days I noticed that web apps are mostly a bunch of map, filter and doseq; even reduce feels quite unusual. Libraries and compilers are not so straightforward.

nilern 2021-04-07T18:50:29.236900Z

https://github.com/pixie-lang/pixie put transducers more at the bottom; but it still has seqs

raspasov 2021-04-07T18:53:44.237200Z

I don’t recall him saying he wouldn’t have seqs; I remember it was a short comment/sentence rather than a fully articulated argument; Don’t want to speculate on what the exact idea of transducers vs. seqs would be;

raspasov 2021-04-07T18:54:04.237400Z

@nilern My language before Clojure was also PHP!

raspasov 2021-04-07T18:54:32.237600Z

The 2nd best! 😝

🏆 1
nilern 2021-04-07T19:01:00.237900Z

> I was taught assembler in my second year of school. > It's kinda like construction work — with a toothpick for a tool. So when I made my senior year, I threw my code away, > And learned the way to program that I still prefer today.

😄 1
Michael Gardner 2021-04-07T19:07:10.238200Z

yeah, that History of Clojure quote is likely what I was thinking of. I'll take a look at pixie

Ed 2021-04-07T19:25:21.238400Z

I think he said something along the lines of "I wouldn't have made sequences lazy by default if I'd thought of transducers first"

✅ 1
Ed 2021-04-07T19:25:58.238600Z

maybe in this? https://www.youtube.com/watch?v=6mTbuzafcII

Ben Sless 2021-04-07T19:29:00.238900Z

dedupe is a good example of how things would have looked differently had transducers been around from the start (probably)

Ben Sless 2021-04-07T19:29:26.239100Z

The arity which accepts a collection is just:

([coll] (sequence (dedupe) coll))

Jan K 2021-04-07T20:13:17.241900Z

Sometimes the transducer solution forces you to hide mutable state in them, where with reduce you could just use the state argument, which feels like "cleaner" FP. I wonder if it would be possible to reinvent transducers so they would get a state argument passed in (like reduce) to somehow avoid mutation inside.

nilern 2021-04-08T07:56:36.246900Z

The state is not as encapsulated (in the sense of the ST monad) as say, the transients inside into but I think transduce, into et al. do encapsulate it so it is only a problem when calling transducers directly which basically only happens in library code

2021-04-09T01:17:07.251400Z

I do think that state in transducers does kind of make it harder to have a parallel transduce no? similar to the reducers fold?

nilern 2021-04-09T13:16:11.270400Z

I guess so although things like drop are not parallelizable anyway

1
nilern 2021-04-07T20:18:41.242Z

Might as well slap an arbitrary monad in there while you are at it 😜

2021-04-07T20:24:49.242200Z

You could replicate something like that with a transducer like the xform library's reductions https://github.com/cgrand/xforms/blob/62375212a8604daad631c9024e9dbe1db4ec276b/src/net/cgrand/xforms.cljc#L491

lilactown 2021-04-07T20:41:09.242600Z

you would need the reducing machinery to be aware of the state attached to the pipeline of transducers

blak3mill3r 2021-04-07T23:50:05.245600Z

I thought it might've been in this talk, not sure https://www.youtube.com/watch?v=4KqUvG8HPYo