-
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 permutations for non-empty lists #68
Comments
I suggest to name it |
Doesn't the E.g. |
@JakobBruenker wrote:
Dunno. I see no pretext for this in |
If we go with the precedent set by |
I'm in favor of deprecating Data.List.NonEmpty.permutations :: [a] -> NonEmpty [a] I think we can get away with this because people really don't use |
@kindaro could you please clarify what exactly is being proposed here? |
I propose to add a function that does the same as |
@kindaro in this case I mark this idea as awaiting a proper proposal. Participants are encouraged to come up with one. |
proposal № 68Add motivationThere is a function proposalAdd a function Furthermore, add a note to the documentation of implementationpermutations :: [a] -> NonEmpty [a]
permutations xs0 = xs0 :| perms xs0 []
where
perms [] _ = []
perms (t:ts) is = foldr interleave (perms ts (t:is)) (permutations is)
where interleave xs r = let (_,zs) = interleave' id xs r in zs
interleave' _ [] r = (ts, r)
interleave' f (y:ys) r = let (us,zs) = interleave' (f . (y:)) ys r
in (y:us, f (t:y:us) : zs) |
I would argue that the permutation of an empty list is a degenerate (trivial) case and can be checked with a pattern match. Incorporating the semantics for a monoidal identity within a function tends to be a mistake. Hence a function with a more useful type signature would be:
Expect the library user to pattern match on Three important considerations:
|
Cf. #67, CC @hdgarrood. |
I’m personally inclined to agree with @recursion-ninja in that I like the sound of a |
Sticking with the naming convention established by Data.List.NonEmpty.group :: (Foldable f, Eq a) => f a -> [NonEmpty a]
Data.List.NonEmpty.group1 :: Eq a => NonEmpty a -> NonEmpty (NonEmpty a) I propose adding Data.List.NonEmpty.permutations :: [a] -> NonEmpty [a]
Data.List.NonEmpty.permutations1 :: NonEmpty a -> NonEmpty (NonEmpty a) |
Cool, can I go on and do it? |
As a point of information (not an argument either way) which I don't think has been mentioned, the "real" type is |
@kindaro I'm not sure if your question is directed at me but if so, sure |
@tomjaguarpaw as long as the type has more than one possible implementation you can always add more information, e.g. in this case that the resulting lists must contain not just the same number but exactly the elements provided in the input list. Though since |
So, what is the next step in the process? I am lost. |
@kindaro would you like to stick to your original proposal or add |
@recursion-ninja @hdgarrood You can help me by providing an implementation for |
I can certainly do this. |
I finished a version just before I saw your response, @recursion-ninja: import qualified Data.List.NonEmpty as NE
import Data.List.NonEmpty (NonEmpty(..))
import Data.Foldable
permutations1 :: NonEmpty a -> NonEmpty (NonEmpty a)
permutations1 xs0 = xs0 :| perms (toList xs0) []
where
perms [] _ = []
perms (t:ts) is = foldr interleave (perms ts (t:is)) (permutations is)
where interleave xs r = let (_,zs) = interleave' id xs r in zs
interleave' _ [] r = (ts, r)
interleave' f (y:ys) r = let (us,zs) = interleave' (f . (NE.cons y)) ys r
in (y:us, f (t:|y:us) : zs)
permutations :: [a] -> NonEmpty [a]
permutations = maybe ([] :| []) (fmap toList . permutations1) . NE.nonEmpty However, it's possible that this performs slightly worse than keeping the original |
After some benchmarking, it looks like it makes more sense to keep (To be clear though, I stand by the |
Ah, there is also this pretty simple solution: permutations1 :: NonEmpty a -> NonEmpty (NonEmpty a)
permutations1 xs = NE.fromList <$> permutations (toList xs) It uses a partial function (but isn't partial itself), but the upside is that it's significantly faster than the version I posted above, almost as fast as (I'm benchmarking these by deepseqing the result, FWIW - or to be more precise, using criterion's |
Here is the draft pull request to GHC. @Bodigrim Dear Andrew, please activate whatever next steps need to be activated. |
My immediate reaction would be to add Data.List.permutations1 :: [a] -> NonEmpty [a] and maybe Data.List.NonEmpty.permutations :: NonEmpty a -> NonEmpty (NonEmpty a) But then seeing @JakobBruenker comment above the Data.List.NonEmpty.permutations :: [a] -> NonEmpty [a]
Data.List.NonEmpty.permutations1 :: NonEmpty a -> NonEmpty (NonEmpty a) after EDIT: note these are that way because FWIW, #67 is the same, and would fit. At least should be considered. I think having Yet, I'd like to have So without an option to do a breaking change (getting to if we could start over, what and where we would do state), there are two suboptimal options, and I don't know which one is less bad. |
Dear CLC members, let's vote on adding +1 from me. Names and types follow existing scheme for |
+1 Doesn't seem like a critical part of the ecosystem, but I have no objections. |
+1 for the additions to Data.List.NonEmpty |
+1 |
Thanks all, 4 votes in favor are enough. Approved. |
It would be weird if only critical changes were accepted. Don't discourage people from making however small improvements. |
Firstly, you may be reading something into my message that I didn't intend. Secondly, perhaps this is not the place to discuss it, but I'm curious to know why it would be weird if only critical changes were accepted. It seems to me that it would be perfectly self-consistent if base were maintained on a critical change basis only. I spend significant amounts of time and mental energy reading through and voting on each CLC proposal (I imagine the experience is similar for other CLC members) and I think it's important for the future of Haskell that volunteer energy is spent in the places where most benefit will be obtained. Naturally, there are strong argument for other approaches too. |
IIRC, when CLC members were asked to nominate first point was https://discourse.haskell.org/t/ann-core-libraries-committee-elections/3215
https://discourse.haskell.org/t/clc-election-january-2022/3839
Is there more than 3 proposal per month nowadays? |
Could you please elaborate? Interpreted one way it sounds like you might be saying I'm not fit to fulfil my role on the committee. I'm sure you didn't mean to say that, so I would welcome a clarification. As a point of information, as can be verified from the issue tracker there have been 33 proposals made since I joined the CLC in February. That's a bit over 6 months and therefore roughly 5 proposals per month, double the estimate of 2-3 per month. There have also been numerous non-proposal issues filed. |
If there are significantly more issues than the ones reaching the vote, and CLC members feel there are too many proposals to look immediately, you could adapt the GHC steering committee way:
Then a single member of committee don't need to look at every proposal immediately as issue is raised. Especially, I think it's a waste of time for whole committee to follow the initial bikishedding phase. |
I don't see how saying "I have no objections" and voting in favor of this proposal would discourage people from making similar proposals. |
Sorry, but I read "Doesn't seem like a critical part of the ecosystem" as a snarky comment "why you bother me with this". |
Thank you for clarifying your interpretation. I can confirm that my comment was not intended to be snarky, but I shall bear your comment in mind and try to communicate less ambiguously in the future. I would also appreciate it if in future, rather than making such assumptions, you asked for clarification. |
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 🙂 @kindaro could you share a status update on the implementation and what are next steps? Also, please do let CLC know if you need any help, so we can coordinate and prioritise approved proposals accordingly! |
@chshersh The only reason for the delay is an onset of overwhelming sadness. I am trying to get over it. Summer is coming, it will get better. I remember that there are 2 pull requests to GHC that I opened and need to see through. Nothing technically challenging. I just need to put myself together. Thank you for stepping up to track the progress of all approved CLC proposals, and your other efforts before that. We are blessed to have you. |
@kindaro Sending you some support 🫂 If you need an extra review or some thoughts on the PRs, feel free to ping me! |
Data.List.permutations
return a NonEmpty
?
Currently we have:
However, you may observe that any list has at least one permutation. For example, the empty list's only permutation is the empty list itself, so:
This behaviour is also theoretically sound since permutations of a list are a model of a symmetric group and a group always has at least one element.
It is nicer to have to drop from a
NonEmpty
to a list than to lift from a list toNonEmpty
, since the former is safe while the latter requires the unsafe handling of the spurious case of the list of permutations being empty. Therefore I propose to add a function that does the same aspermutations
but returns aNonEmpty
of lists.See also kowainik/relude#385.
The text was updated successfully, but these errors were encountered: