I never claimed that Clojure (or transducers, etc) is "more pragmatic than Haskell", I said "Clojurians engage with diverse ideas pragmatically".
> how exactly does your runtime generative tests are different from statically derived strategies
Spec generators are derived from predicates, not types - which inverts the usual QuickCheck problem where Int generates any Int and you have to write newtypes or custom Gen instances to narrow to "ages 1-120." Spec also has :fn specs that assert relationships between args and return values, which base QuickCheck/Validity don't give you natively (you'd reach for Liquid Haskell). And `instrument` validates real calls in dev, not just sampled properties.
You seem to be operating on a single axiom: types + purity + laziness are the correct solution to the problems worth solving. Given that axiom, every Clojure design choice in your eyes either (a) a patch for not having them, or (b) an unnecessary abstraction that falls out of having them. There is no version of reality in which Clojure can be credited with solving something for you, because the axiom forecloses it.
This is an unfalsifiable position, any additional technical arguments would be wasted. You don't even try to evaluate my counterexamples, because the axiom tells you the counterexamples must be wrong in some way you haven't yet articulated to yourself.
Okay, please, give me Haskell code that takes one composed transformation and applies it, unchanged, to a vector, a lazy seq, a channel, and a pure fold. Not 'here is pipes, here is conduit, here is streaming, here is foldl library' - one piece of code, four consumers. That's the thing you have dodged four times in the other thread.
Clojure didn't ignore static types or the pure/effectful distinction - it made a deliberate decision to optimize for different values. Framing deliberate trade-offs as ignorance is often itself a screaming display of ignorance.
> I said "Clojurians engage with diverse ideas pragmatically".
then you said nothing and contributed nothing to your points, as everybody else "engage with diverse ideas pragmatically". It also so happened that engaging allows for rejection of inferior ideas, which is what transducers are. I can compose around any Python iterable the same way you claim is important to transducers, but do you know what I lose if I engage with the pragmatic Python and Clojure? I lose precision and further optimizations.
> You seem to be operating on a single axiom
How about you abstain from drawing wrong conclusions and actually focus on being precise
> Spec generators are derived from predicates, not types
What do predicates operate on? QuickCheck builds bounded ints within their `minBound` and `maxBound` of the type, as the basis of Int spec deriving. There's no difference and no inversion of intent if your strategy for your newtype actually produces a spec deriving from 1-120 range. If you say there's a thing called Age, and it being a subset of Int or Nat ranges, you do define the Age and its bounds as part of your spec, and there's zero inversion to what clojure spec does. I'm beginning to suspect that I'm conversing with a prompt output.
> Okay, please, give me Haskell code that takes one composed transformation and applies it, unchanged, to a vector, a lazy seq, a channel, and a pure fold. Not 'here is pipes, here is conduit, here is streaming, here is foldl library' - one piece of code, four consumers. That's the thing you have dodged four times in the other thread.
Certainly, I'll do that as soon as you provide me with the example of a transducer tracking effects separately from pure evaluations. We want to be on the same page, don't we? I want to compose my effects without ambiguity, so hurry up.
> Clojure didn't ignore static types or the pure/effectful distinction - it made a deliberate decision to optimize for different values.
lol, it actually ignored it, but you're too perky to simply admit that as if your future depends on it.
> QuickCheck builds bounded ints within their `minBound` and `maxBound`
Yeah, your narrow technical note isn't wrong here (I should've used less trivial example), but the broader differences still hold - spec operating on map shapes without lifting data into types, arg/return relationships without reaching for Liquid Haskell, etc. This is much longer discussion that requires its own thread, unrelated to transducers.
> I can compose around any Python iterable the same way
No, you can't. Python iterables are not uniform across: strict collections, lazy sequences, async channels, arbitrary reducing step functions. itertools composes over iterables. It does not compose over asyncio.Queue, a trio memory channel, or a user-supplied step function. The transducers are specifically about the reducing function as the point of composition, which decouples the transformation from whatever produces or consumes values. Python's iterator protocol is a narrower abstraction. Show me some Python code that applies one composed transformation, unchanged, to an iterable, an asyncio.Queue, and a user-defined reduce function. You can't, because the protocol doesn't support it. Congratulations, now you're complaining on a third language without properly understanding the topic at hand.
> provide me with the example of a transducer tracking effects separately from pure evaluations
Transducers aren't an effect-tracking system because Clojure's language doesn't track effects in types. Asking for a Clojure abstraction that tracks effects is like asking for a Haskell library that works without the type system. It handles effects through different mechanisms, and transducers are orthogonal to effect tracking by design. Effect separation is not a goal of transducers, just as uniform multi-consumer application is not a goal of lazy evaluation.
> lol, it actually ignored it, but you're too perky
This is factually wrong. Hickey's talks (Effective Programs, Maybe Not, Clojure core.typed, the explicit refusal to adopt static types) are public, specific, and reasoned. You can absolutely disagree with the reasoning. Calling deliberate, argued design decisions "ignored" is either ignorance or dishonesty.
You're defending a hierarchy: typed+pure+lazy on top, everything else is a degraded attempt at the top. Within that hierarchy, Clojure can't contribute anything original, by definition - anything Clojure does either (a) duplicates what types+purity already give you, or (b) is a workaround for not having them.
I'm defending something subtler and harder to argue: that different design axes exist, that Clojure's choices are coherent given its axes, and that "this language's solution to X is a workaround for not having Y" is a framing choice, not a technical claim. I am also rhetorically disadvantaged, because "X is just a workaround" is a punchy dismissal and "X is a coherent choice within a different design space" is a paragraph.
I'm not perky about any of it, this isn't a Haskell vs. Clojure debate for specific use cases, you're arguing just for the sake of it. You're not learning, not probing ideas, not stress-testing your own position, nor are you giving me an opportunity for any of that on my side. Language-tribal arguments on HN are a genre, and you're writing in that genre. I hope you had fun, and please don't you dare calling me "a prompt output" - I spent time and energy arguing in vain, about nothing, at least have some human decency to acknowledge that.
> how exactly does your runtime generative tests are different from statically derived strategies
Spec generators are derived from predicates, not types - which inverts the usual QuickCheck problem where Int generates any Int and you have to write newtypes or custom Gen instances to narrow to "ages 1-120." Spec also has :fn specs that assert relationships between args and return values, which base QuickCheck/Validity don't give you natively (you'd reach for Liquid Haskell). And `instrument` validates real calls in dev, not just sampled properties.
You seem to be operating on a single axiom: types + purity + laziness are the correct solution to the problems worth solving. Given that axiom, every Clojure design choice in your eyes either (a) a patch for not having them, or (b) an unnecessary abstraction that falls out of having them. There is no version of reality in which Clojure can be credited with solving something for you, because the axiom forecloses it.
This is an unfalsifiable position, any additional technical arguments would be wasted. You don't even try to evaluate my counterexamples, because the axiom tells you the counterexamples must be wrong in some way you haven't yet articulated to yourself.
Okay, please, give me Haskell code that takes one composed transformation and applies it, unchanged, to a vector, a lazy seq, a channel, and a pure fold. Not 'here is pipes, here is conduit, here is streaming, here is foldl library' - one piece of code, four consumers. That's the thing you have dodged four times in the other thread.
Clojure didn't ignore static types or the pure/effectful distinction - it made a deliberate decision to optimize for different values. Framing deliberate trade-offs as ignorance is often itself a screaming display of ignorance.