-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add {-# WARNING #-} to Data.List.{head,tail} #87
Comments
What do you see as the advantage of this over using a tool like |
Can you explain further? I dont see how All of these have a non-partial non-drop-in replacement: headSafe = fmap NonEmpty.head . nonEmpty
lastSafe = fmap NonEmpty.last . nonEmpty
tailSafe = fmap NonEmpty.tail . nonEmpty
initSafe = fmap NonEmpty.init . nonEmpty Note that since the flag to disable this warning is the same flag to disable deprecations, this proposal effectively deprecates head and tail, which I'm not sure we should do in a one-off operation. We don't do this for any other partial function [in base]. I don't think head and tail are special enough to make an exception. Now, maybe if we had a push to deprecate all partial functions in base (which I'm not opposed to), I'd be on board... |
I would strongly oppose this change. It completely ignores users of GHCi, educational users, and other situations in which there's absolutely zero reason to avoid head. Even if you take it on principle that using head is somehow "bad behavior" that should be punished, it also pushes users toward the wrong solution. Uses of head/tail happen when you're certain the input is non-empty, and the default solution there, whenever possible, should be change the type to NonEmpty, not to add useless boilerplate dealing with an impossible branch in your code. All of this might be overlooked if there were a compelling benefit. But having two fewer partial functions (and, frankly, quite possibly two of the most obviously partial and therefore least problematic) doesn't change much when there are so many more remaining. Honestly, this would feel to me like an effort to deliberately annoy users the Haskell community disagrees with and drive them away, more than a way to help anyone. |
How would this affect users of Liquid Haskell? |
I'd argue that you should still avoid it in these cases, especially education, since you don't want to teach people bad habits that they have to later unlearn when they start writing production code.
I agree with this, but I don't see why it's a reason not to make this change. (Or was this in regard to the specific text of the warning pragma, rather than its existence? If so, then I agree it should probably mention NonEmpty too.)
Sure, it doesn't change much, but it's still a small step in the right direction. |
I agree with this proposal. It's a great way to move the language forward, because it will prod both newcomers and old hands to use safer alternatives such as pattern matching.
@Boarders
@Boarders really? What's the evidence for this?
@brandonchinn178 agree, let's do this! |
Please don't do this. There are perfectly reasonable uses for I would be fine with adding these warnings by default if there was an easy way to disable them, but |
I fully support this proposal 💛 I'm yet to see a use case for A warning doesn't take these functions away. It just warns about common pitfalls. So I see no harm in it.
Quite the opposite, it actually helps educational users because there's a warning about potential dangers of this function.
Haskellers would rather suppress useful warnings than improve code maintainability 😌 We all are "Make illegal states unrepresentable" unless it's a specific partial function we have strong feelings about 😮💨 My suggestion to the proposal is to slightly change the wording to reflect the fact that the functions fail on empty lists (because it might not be obvious for Haskell beginners): -{-# WARNING head "This is a partial function, use pattern matching or Data.List.uncons instead" #-}
+{-# WARNING head "This is a partial function, it throws an error on empty lists, use pattern matching or Data.List.uncons instead" #-} |
The most legitimate use I've seen is the (FWIW, |
I think this is really highlighting the need for something like ghc-proposals/ghc-proposals#454 in order to more painlessly make subtractive improvements to the language (and libraries as well!). |
Sometimes whether the list is empty or not is ancillary to the logic at hand. Here's an incredibly trivial example: case product xs of
1 -> foo
n -> bar n (head xs) In the second case, we know for a certainty that the list is not empty because I understand that you usually shouldn't use these functions, but making it a warning seems misguided to me for three reasons.
EDIT: To be clear, I'm not saying I think they should still be in |
It sounds like this is a good use case for a specially-named version of Footnotes
|
What if the partial functions being deprecated were under a new flag? Or if that's not enough... heck, give each partial function it's own flag if it clears a path to no partial functions in base. |
This will negatively affect those who use |
Do you mean "this will negatively affect those who use |
Well yes, and those who use Liquid Haskell too. |
Regarding Regarding the interaction of |
It seems to me that the proposal is predicated on the assumption that there are insignificantly few cases where the logic of a computation dictates non-emptiness, and therefore, the proponents mention ad-hoc |
I'm not the proposer, so I can't speak for his assumptions, but that is not my understanding. My understanding is that the assumption is that those who have genuine cause to use |
Why isn't it the other way around? Power users already know what they're doing, and for beginners there could be |
Firstly, I'm a "power user" and I wish Secondly, power users are more likely to know how to tweak their tools to get desired behaviour, and beginners are less likely to know. That suggests that the the behaviour that requires configuration shouldn't be the one that we want beginners to be exposed to. |
I'm a power user and I know that the future is going to be refinement/dependent where partiality of
beginners will not benefit from this warning, because aside |
It's indeed a contrived example. I'm not surprised it's possible to create an artificial example but do people actualy write the code like that? Here's a better way to write this particular snippet in a less "smart" way, without using case xs of
[] -> foo
y : _
| all (== 1) xs -> foo
| otherwise -> bar (product xs) y
|
I personally like how PureScript solved this with the Maybe ghc-proposals/ghc-proposals#454 would allow a similar solution in Haskell. |
I like the idea of a |
I'm not a fan of this proposal but I was never bothered by the existence of basic partial functions like |
I'm enthusiastic about removing partial functions from 'base'. Partial functions aren't the future of this language, and while the best time to start "officially" discouraging their use was 10 years ago, now is the second-best time. |
Beginners usually meet head and tail first @avanov . Their relationship with partial functions start with this first impression. I believe that pushing beginners away from partial functions also solves another common question that demonstrates a flawed mental model: "How do I get the value out of the Monad? " Restating things, the non-obvious benefit here is pushing beginners to look for the use in these "wrappings" rather than say "getting rid of maybeness". |
Wouldn't using a custom pattern match with |
I'm trying to summarise the state of this proposal as part of my volunteering effort to track the progress of all
Please, let me know if you find any mistakes 🙂 EDIT: This is merged now. Latest discussion: |
Remove In short, because the core libraries often use plain lists where non-empty lists could be used, warnings thrown by In the wild: P.S.: Apparently |
The result of the vote was that there should be a |
Please refrain from reopening proposals which have reached the end of their life cycle. The policy is that CLC is open to review past decisions, but only if there was a material change of circumstances since the original deliberation. If that's the case, feel free to open a new issue. |
And other issues after upgrading to GHC 9.8 References: - haskell/core-libraries-committee#87 - https://github.com/haskell/core-libraries-committee/blob/main/guides/warning-for-head-and-tail.md
These cause deprecation warnings: haskell/core-libraries-committee#87
These cause deprecation warnings: haskell/core-libraries-committee#87
These cause deprecation warnings: haskell/core-libraries-committee#87
Haddocks for
Data.List
(technically,GHC.List
) warn againsthead
andtail
on the ground of their partiality.I propose to promote these warnings to the pragma level as per MR !9290:
I do not propose any further steps such as deprecation or removal of these functions. This is deliberately as conservative as possible. See #70 for a wider discussion of a wider proposal.
Why only
head
andtail
? Because these are functions, for which the widest range of replacements exist, almost always allowing for a safe, concise and local fix (see examples below). E. g., forinit
/last
there is currently no such replacement (one must push for addition ofData.List.unsnoc
first), and things like!!
andmaximum
are even worse.Why
{-# WARNING #-}
and not{-# DEPRECATED #-}
? Because deprecation implies a future removal, and ambitions of this proposal are much smaller. It's already enshrined inbase
that these functions deserve a warning, we just promote its visibility, which should be less controversial.The impact of the change is that users of
head
andtail
will receive a GHC warning message. This is not an error and does not prevent from compilation, thus is not a breaking change. Users are recommended to follow the suggestion, or disable-Wno-warnings-deprecations
(which is a sensible thing to do, for example, in a test suite), but they are also free to do nothing at all. Old packages will continue to work.To avoid any confusion,
-Wno-warnings-deprecations
suppresses{-# WARNING #-}
and{-# DEPRECATED #-}
, but not any other GHC warnings. Those, who enabled-Werror
, can pass-Wwarn=warnings-deprecations
to downgrade this particular group back from errors to warnings. GHCi users can put:set -Wno-warnings-deprecations
into their.ghci
config.There is a concern that
-Wno-warnings-deprecations
disables all{-# WARNING #-}
and{-# DEPRECATED #-}
, whatever the source. However, current Haskell ecosystem rarely makes much use of them, so I believe it is still a palatable compromise between seeing no warnings and making no changes.Hardcore fans of
head
andtail
, who are not satisfied with disabling warnings, are welcome to create a local file or even release a package, providing, say,Data.List.Partial
, containing original definitions ofhead
andtail
without{-# WARNING #-}
. I'm however opposed to introducing suchData.List.Partial
intobase
itself: we won't be able to root it out ever.GHC proposals ghc-proposals/ghc-proposals#454 and ghc-proposals/ghc-proposals#541 propose extensions to GHC warnings mechanism. Unfortunately, neither of them is approved or has a committed implementor, and this status does not seem to change soon, so it would be wrong to speculate on their precise nature. If and when they become a part of GHC, one can indeed ask for a review of
{-# WARNING #-}
pragmas.How would you rewrite
instance MonadFix []
withouthead
andtail
?I'd rewrite it this way:
How would you rewrite this snippet?
Besides options in #87 (comment), one can do this:
or (if you insist on exactly two clauses):
How would you rewrite this snippet?
I'd use a proper library for infinite lists aka streams:
Stream
,streams
orinfinite-list
. E. g.,Stream
provides totalhead :: Stream a -> a
andfilter :: Stream a -> Stream a
, so the snippet can be rewritten in a total way asinfinite-list
can make it even neater offering(0...)
syntax to replace[0..]
.The text was updated successfully, but these errors were encountered: