This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-26
Channels
- # announcements (1)
- # beginners (42)
- # biff (11)
- # calva (15)
- # cider (3)
- # clj-http-lite (3)
- # clojure (52)
- # clojure-europe (16)
- # clojure-nl (1)
- # clojure-norway (39)
- # clojure-uk (4)
- # clojurescript (52)
- # code-reviews (13)
- # conjure (1)
- # cursive (4)
- # data-science (1)
- # datomic (5)
- # emacs (6)
- # events (3)
- # graalvm (5)
- # hyperfiddle (7)
- # kaocha (14)
- # lsp (11)
- # malli (3)
- # nbb (13)
- # off-topic (87)
- # pathom (15)
- # polylith (23)
- # portal (5)
- # reitit (4)
- # shadow-cljs (110)
- # squint (114)
- # testing (1)
- # vim (13)
One small data point: I use partial
quite a lot. Maybe this is a bad habit. Do most people just use anonymous function shorthand instead?
I can't speak for most people but there are pros and cons of not using it. I think the pros of avoiding it outweigh the cons but some other people think the reverse
I don't want to make a big deal out of this, but here are some notes on partial from a recent conversation: https://gist.github.com/borkdude/b16118aa12af1dac3e487612a7936aad
This is super useful thanks!
general rule in clava is that functions take iterables and return array. now there is a situation with the following code (take 2 (partition 2 (repeat 1))) The partition functions try to put everything in an array and fails. Please provide your feedback as to what is the prefered approach here.
should the partition function be lazy just like repeat. Or should it be lazy if the input is not finite.
Great question. Maybe it would be more consistent if all of these returned iterables
but when one wanted a concrete array, one could do (into [])
probably which is then safe to use more than once
summoning @lilactown and @corasaurus-hex here too
Let's continue in this thread. @corasaurus-hex @lilactown
using iterables all the way through and then relying on the user to call vec
or do (into []
does seem like a viable solution
and it would not be breaking if we decide later on that take
etc will return a LazySeq-like thing
that or getting rid of infinite sequences
yeah, I think it's convenient to have infinite sequences for things like:
(map (fn [i e] ..) (range) coll)
I wonder if we should make something like a cloneable iterable, so that in iterable-consuming functions we could clone the iterable to preserve the original
I'm not sure how to make iterables cloneable but yes
I do love infinite sequences, they're so useful
or maybe we require chains of iterables to be called with some containing function similar to comp?
I'm interested to hear @lilactown's thoughts on this
or make iterable-returning versions of these functions and users need to be aware of which they're using?
like repeat
can always return an iterable but we could have an iter-partition
that could return an iterable instead of an array
it would be damn convenient if you didn't have to import another namespace for this, since it's so much used in CLJS
maybe have iter-repeat
with arity of 1 and have repeat
have an arity of 2?
this would be a bit annoying with tools like clj-kondo which already know the types of repeat
with 1 argument
or make repeat
's arities return different types (iterable for 1, array for 2)
yeeeaaaaahhhhh that's true
even with an arity of 2 you might not want all of repeat's available values
I think for now it would make a lot of sense to return iterables and concretions should be done using into or vec
that sounds like the simplest solution to me
I think we could implement custom data structures that cache their results, but there's also a trade-off: using iterators directly is likely faster and the 99% pattern in CLJS is probably to use composed lazy-seqs once... we could try this for a while and when it doesn't turn out to be good enough, implement some custom data structure stuff
there was an explicit decision (i thought) early on that we would make core functions like map, filter, etc. eager
and tell people to use transducers for composing over potentially infinite sequences
is it that people are trying to write code, and we don't have a solution for it yet because we haven't implemented transducers?
@lilactown I think the whole seq ~ iterator resemblence came later. The usage of iterator-returning functions like (range)
came later. We have an oppurtunity to have a difference between map and mapv. Even with transducers, the input can still be a "lazy" iterator.
Having some seq functions be eager and others return an iterator could also be a little confusing.
Just because we made a decision early should not be a reason to stick with it, I'm learning new things as we go every day. Although we should document these choices to remember why we made them.
And this project doesn't promise any stability as of now, I suggest we take at least a year to figure out how to best to things
Also I wasn't that aware of JS iterators, coming from CLJS mostly, I've never really been exposed to them :-)
But there is a serious trade-off of course, having map be a function*
with yield
probably has performance overhead
one concern would be interop - does react etc. play well with iterator results rather than array results?
one pro would be more CLJS-like code, e.g. what @UGFGYK4GM posted:
(take 2 (partition 2 (repeat 1)))
yes, you could do this using transducers: (into [] (comp (partition 2) (take 2)) (repeat 1))
but it's more verbose and using transducers isn't always that important, until you need the performance
e.g. in CLJS you can return a lazyseq to React and since it's iterable, React will iterate it like any array
I remember Rich saying that if he could go back, he would have designed the core lib to focus on transducers over lazy seqs
there's a tension between supporting existing Clojure patterns vs. iterating on Clojure's original design
He probably said that right after he introduced transducers, does he still say that today? And this doesn't change the goal of clava to re-use existing CLJS idioms in JS
I think we have some wiggle room to experiment with iterators for the non-v functions though
an alternative design i've thought about is taking over the 2-arity version of seq ops to compose transducers instead
(into [] (take 2 (partition 2)) (repeat 1))
the clunkiest part of reading & writing transducers to me is the (comp ,,,)
I'm wondering about separating transducers... if we do that, I'm betting people will use them even less.
I'm not so much for changing the semantics of core functions to behave totally different. clj-kondo will be very confused about this for example
perhaps the extra transducer code isn't that much of a deal to have it inside core.js
yeah i'm feeling pulled towards not changing anything about the core seq ops. 1-arity returns transducer, 2-arity does a lazy seq
I have a WIP of the transducer protocol. I'll open up a draft PR either today or tomorrow
I'm making some improvements to JSX, there was one bug when you had a map as an attribute. Currently there are no tests for JSX, but I'm doing this:
$ ./node_cli.js --show --no-run -e '#jsx [:div {:dangerouslySetInnerHTML {:_html "<i>Hello</i>"}}]'
<div dangerouslySetInnerHTML={({ "_html": "<i>Hello</i>" })}></div>;
I wonder how I could make unit tests for this to verify the JSX is valid.Draft PR for transducers: https://github.com/clavascript/clavascript/pull/137/files?diff=unified&w=0
seriously considering pulling it into core.js tho based on this thread https://clojurians.slack.com/archives/C03U8L2NXNC/p1661544494501149?thread_ts=1661522971.130269&cid=C03U8L2NXNC
I wonder how you get into such a situation. I usually start with a branch instead of committing on main locally
I think you should enable this maybe?
Do not allow bypassing the above settings
The above settings will apply to administrators and custom roles with the "bypass branch protections" permission.
it also prevented me from force pushing with whatever the default is, but didn't prevent me from pushing lol
btw, transducers-js seems a lot of code... are you going to implement all of that inside of clavascript - or should we recommend people who want to use transducers to actually use that library?
@lilactown when map
would return an iterator, and one would do (vec (map inc (map inc (range 1000))))
- what would be the benefit of the transducer approach compared to this?
No, I mean, if people want to have the transducers functionality, they could also just use rambda or transducers-js directly
also, still interested in the answer to this: https://clojurians.slack.com/archives/C03U8L2NXNC/p1661550542608869?thread_ts=1661550226.814589&cid=C03U8L2NXNC - wouldn't this already get you most of the benefits?
maybe we should benchmark it. it's possible that generators are more performant than lazy seqs
the issue seems to happen when:
1. I have two remotes: origin
which points at my fork lilactown/clavascript
, and upstream
which points at clavascript/clavascript
2. I fetch upstream/main
and create a new branch
3. the default "merge" remote is set to upstream/main
4. I naively press P u
like I've built my muscle memory to