Open gampleman opened 1 year ago
I have more copies of nTimes
around my codebases than I'm comfortable admitting. I'd be fine with having these functions in core-extra, even if some of them are a bit controversial! (eg. flip
could be)
In the past elm install
-ing basics-extra just for one helper didn't seem worth the effort to me but if part of core-extra I can imagine myself using some of these functions more, for better or for worse.
for better or for worse
I think that's the key question. I definitely have most of these helpers defined a few times in my projects as well. But is it a pattern that should be encouraged? On the other hand, there is a good few functions in core-extra that probably shouldn't be encouraged already...
I think it needs to boil down to what you see this package as: is it opinionated and contains only functions that you can vouch for, or is it a merge of the existing -extra packages with all their (better/worse) choices?
I'd love Function.Extra.nTimes
but don't care about the fate of curry,uncurry
for example. But there might be folks wanting to use core-extra instead of basics-extra that would be missing those functions. They can still vendor those few discouraged functions, maybe the benefit of core-extra without those functions outweighs their lack?
Thought: It’s also possible to forbid functions using elm-review, if there’s one you vehemently disagree with. I would probably need to forbid curry
and uncurry
to stop myself from using them.
OK, here's an idea on how to solve the dilemma:
Adopt a little emoji icon, like 💡 and explain in the readme:
💡 Not all functions in this package are generally recommended for all Elm use cases. There are a number of ways to write Elm, but some of those tend to lead to code that can be hard to grasp for beginners or create code that might be fun to write but hard to read. When you see this icon, it is the opinion of the maintainers that a better pattern exists.
Add little sections with 💡 to the docs to a bunch of the more questionable functions, explaining why they might be bad for applications (i.e. say from the perspective of commercial team-based development).
Create an elm-review rule that enforces these opinions.
I'm not super confident in this plan, since it creates a decent heap of extra work, that I personally am not super excited about. But there is already some questionable code and so far the feedback I've been hearing seems to be strongly against removing functionality.
On this specific proposal, my feeling regarding controversiality is roughly like this:
uncurry
and curry
: we mostly don't want them, as they tend encourage confusing code. The main reason to include them is that we already have them in Basics.Extra. (Also uncurry
already exists in the less confusing guise of Tuple.Extra.apply
.)flip : (a -> b -> c) -> b -> a -> c
, but it's also so trivial to define that I'm pretty fine to just define it inline when I want it.toFixpoint
has been useful to me, but perhaps its not a well known enough concept? I'd be for including it.while
is useful for porting imperative code. That's basically the entirety of its use case. As someone who has done more than their fair share of that, I'd find it useful, but again perhaps that's too niche. And again, perhaps in other contexts it's an imperative clutch that we shouldn't be encouraging?nTimes
is basically a for loop, so again there's a porting use case. It also tends to show up in simulation code and so on.Definitely a vote against curry/uncurry
, they lead to pointlessly pointfree code, same for flip
.
toFixpoint
is innocuous but not sure if generically useful enough to warrant inclusion.
nTimes
is definitely generic enough and "clean".
Good point on nTimes
and while
being useful for porting!
Not sure if there is much appetite for this, but a Core-ish type is the function type. There are a bunch of helper functions to do with functions:
uncurry : (a -> b -> c) -> (a, b) -> c
curry : ((a, b) -> c) -> a -> b -> c
a -> b -> b
,(a -> c) -> (b -> c -> d) -> a -> b -> d
, yada yadatoFixpoint : (a -> a) -> a -> a
and perhapstoFixpointWithLimit : Int -> (a -> a) -> a -> Result a a
while : (a -> Bool) -> (a -> a) -> a -> a
anddoWhile : (a -> a) -> (a -> Bool) -> a -> a
nTimes : Int -> (a -> a) -> a -> a
etc...
Thoughts? Opinions?