-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Foldable.toList potentially inconsistent for Map #1831
Comments
This same issue would show up for |
@johnynek I suppose |
I don't know how we can possibly get congruence here since you can trivially distinguish values that are ostensibly equal. Universal properties FTL yet again. Do we punt and say yeah that's the risk you take with non-parametric data types, or remove the instances for I'd like to push past this as it seems to be the only thing holding up the Monocle port. |
I have a selfish preference for the Though I guess we can put it in |
Are you suggesting we constrain the instance to :-\ |
Oh I totally forgot about |
I wonder if it is possible to have a Regarding Monocle, I need to review the traversal law. Maybe it is just too strict. |
I have been thinking a bit more about this and I find it worrying that test("traverse order") {
import cats.{Id, Traverse}
import cats.data.Const
import newts.FirstOption
val T = Traverse[Map[Int, ?]]
val x = Map(1 -> "abc", 2 -> "cde")
def liftId[A](a: A): Id[A] = a
def store[A](a: A): Const[FirstOption[A], A] = Const(FirstOption(Some(a)))
val first = T.traverse[Const[FirstOption[String], ?], String, String](x)(store).getConst.getFirstOption
val traverseFirst = T.traverse[Const[FirstOption[String], ?], String, String](
T.traverse(x)(liftId)
)(store).getConst.getFirstOption
first should be (traverseFirst) // Some("abc") was not equal to Some("cde")
} |
It seems unresolvable to me if we have instances for |
I talked to a friend who helped clarify it for me. The problem is that the relation |
Makes sense, can't assume |
Thanks, @tpolecat I need to read more about this. I always consider I believe the problem remain regarding the fusion rule for traverse (from the paper): However by changing the order in |
I think we need to formulate the objections here into a PR which adds some laws to I am not sure we want that I think we definitely want: |
@johnynek We are violating this law for Map. You're right, we should add a test for this law for all Traverse instance |
So I've thought about this for some time now including some related issues #1966 and #1927.
Both of the first two incur the penalty of having to sort the keys whenever the operation in question is performed. Out of those two, I think folding is more common, so I'd rather reorder on Then we have the issue of
Out of those I only really like 2 and 5, WDYT? |
To clarify number 5 up there would be something like this: @typeclass trait TraverseUnordered[F[_]] {
def traverseUnordered[G[_]: CommutativeApplicative, A, B](sa: F[A])(f: A => G[B]): G[F[B]]
} We could define that for |
I vote for deprecating the current |
To me, the highest priority is adding the law to check. We could be violating this elsewhere that we have not noticed. I think requiring I agree that the As far as how quickly to remove vs. just deprecate I don't know. I'm usually +1 on a slow cycle there so people don't get totally burned trying to do upgrades (I already fear cats 1.0 is going to be painful for large codebases). On a side note, I wonder if we should bring alley-cats into this repo so it is easier to version together and move lawless, but often useful instances there. |
There's probably a way to design our way out of this but I don't think it's worth holding up 1.0 (it's been like this forever in scalaz). So for now I would be fine either deprecating these instances or moving them to alleycats immediately (traversing maps isn't super common so I imagine the impact of a package change won't be huge). Also 👍 for bringing alleycats into the repo. |
agree, alleycats needs more attention, right now it's been left in a dark corner. I submitted an issue to move it into typelevel org and even I totally forgot about it. |
We can add Foldable to |
@tpolecat I wouldn't say traversable for Map is so rare. You can't build a |
I propose the following plan
|
I agree 2 and 5 here: #1831 (comment) sound like the best way forward. Unordered(Foldable/Traverse) seems tractable and useful for general unordered containers. |
I also agree that we should add the laws to expose this inconsistency. |
fixed by #1972 |
The problem comes from
Map.toList
which is used by cats. As far as I know scalaz side step this issue because it requires anOrder
onMap
keys.You can also see this problem when you use traverse:
The text was updated successfully, but these errors were encountered: