Skip to content
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 SortedMap and SortedSet instances/Move Set and Map instances to Alleycats #1972

Merged
merged 20 commits into from
Oct 30, 2017

Conversation

LukaJCB
Copy link
Member

@LukaJCB LukaJCB commented Oct 16, 2017

Should fix #1966

else fb.map(fb => map2(fa, fb)(f))

override def ap[A, B](ff: SortedMap[K, A => B])(fa: SortedMap[K, A]): SortedMap[K, B] =
??? //fa.flatMap { case (k, a) => ff.get(k).map(f => (k, f(a))) }(scala.collection.breakOut)
Copy link
Contributor

@kailuowang kailuowang Oct 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still WIP? same below

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sorry. I meant to state so in the description 😅

Copy link
Contributor

@johnynek johnynek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added #1973 about my doubts.

var a, b, n = 0
var c = 1;
x foreach { case (k, v) =>
// use the default hash on keys because that's what Scala's Map does
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to do that here actually. Map[K, V] needs to do this because the hash in question in a Map[K, V] is the .hashCode. But I think we can be unconstrained on a SortedMap since it is only using our Order typeclass.

fa.foldLeft(b) { case (x, (k, a)) => f(x, a)}

def foldRight[A, B](fa: SortedMap[K, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
Foldable.iterateRight(fa.values.iterator, lb)(f)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this was actually unsafe since it captures a mutable iterator? I think to make it safe, it needs to have () => Iterator[A] which it can call to get a new one each time (which is another way of saying the Iterable[A] and it calls .iterator internally.

We had some bug related to this in the past. Not sure why we didn't fix Foldable.iterateRight. Actually, it was related, but not exactly the same. See #1716.

@codecov-io
Copy link

codecov-io commented Oct 16, 2017

Codecov Report

Merging #1972 into master will decrease coverage by 0.24%.
The diff coverage is 86.52%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1972      +/-   ##
==========================================
- Coverage   95.49%   95.24%   -0.25%     
==========================================
  Files         298      301       +3     
  Lines        4814     4922     +108     
  Branches      120      123       +3     
==========================================
+ Hits         4597     4688      +91     
- Misses        217      234      +17
Impacted Files Coverage Δ
...s-core/src/main/scala/alleycats/std/iterable.scala 100% <ø> (ø) ⬆️
...in/scala/cats/laws/discipline/ReducibleTests.scala 100% <ø> (ø) ⬆️
...eycats-core/src/main/scala/alleycats/std/set.scala 100% <ø> (+50%) ⬆️
core/src/main/scala/cats/Foldable.scala 100% <ø> (ø) ⬆️
laws/src/main/scala/cats/laws/TraverseLaws.scala 92.3% <100%> (+1.98%) ⬆️
core/src/main/scala/cats/instances/map.scala 90% <100%> (-4.29%) ⬇️
laws/src/main/scala/cats/laws/FoldableLaws.scala 100% <100%> (ø) ⬆️
core/src/main/scala/cats/instances/set.scala 100% <100%> (ø) ⬆️
...ain/scala/cats/laws/discipline/TraverseTests.scala 100% <100%> (ø) ⬆️
...rc/main/scala/cats/laws/discipline/Arbitrary.scala 92.95% <100%> (+0.77%) ⬆️
... and 9 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c4ee747...2aef355. Read the comment docs.

@LukaJCB
Copy link
Member Author

LukaJCB commented Oct 16, 2017

Damn there's no mutable SortedMap pre-Scala 2.12

@LukaJCB
Copy link
Member Author

LukaJCB commented Oct 16, 2017

So the tests fail for 2.11 and earlier for some reason. Will have to investigate

@LukaJCB LukaJCB force-pushed the add-sorted-instances branch 2 times, most recently from 58e6907 to fb37bba Compare October 24, 2017 16:44
@kailuowang
Copy link
Contributor

@LukaJCB I submitted a PR against your branch LukaJCB#2
let me know if that sounds a good idea to you.

@@ -218,14 +218,6 @@ class FoldableSuiteAdditional extends CatsSuite {
checkFoldMStackSafety[Vector](_.toVector)
}

test("Foldable[Set].foldM stack safety") {
checkFoldMStackSafety[Set](_.toSet)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall we replace these two foldMStackSafety tests with SortedSet and SortedMap ones?

@@ -30,7 +30,7 @@ class ParallelTests extends CatsSuite with ApplicativeErrorForEitherTest {
}

test("ParTraverse_ identity should be equivalent to parSequence_") {
forAll { es: Set[Either[String, Int]] =>
forAll { es: List[Either[String, Int]] =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use SortedSet? (Either has Order instance)

type StringMap[A] = Map[String, A]
val intMap: StringMap[Int] = Map("one" -> 1, "two" -> 2, "six" -> 6, "eight" -> 8)
intMap.traverse(validate) should === (Either.left("6 is greater than 5"))
checkAndResetCount(3)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what this regression test is about, do you know? If neither of us are sure maybe we should replace it with a sortedMap one?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently it's about #513. I had to adjust this test slightly, because the order of the Strings matter now, so it wouldn't work if we just change the type of the collection :)

@LukaJCB
Copy link
Member Author

LukaJCB commented Oct 28, 2017

Everything should be addressed now 🎉 Thanks everyone!

implicit def catsStdInstancesForMap[K]: Traverse[Map[K, ?]] with FlatMap[Map[K, ?]] =
new Traverse[Map[K, ?]] with FlatMap[Map[K, ?]] {

def traverse[G[_], A, B](fa: Map[K, A])(f: A => G[B])(implicit G: Applicative[G]): G[Map[K, B]] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add some law that this violates? I hate to remove it if we don’t actually have a law that it violates. I think we can write some (the original ticket had an example). I fear we could have other lawless instances without a law.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done :)


def empty[A]: Set[A] = Set.empty[A]

def combineK[A](x: Set[A], y: Set[A]): Set[A] = x | y

def foldLeft[A, B](fa: Set[A], b: B)(f: (B, A) => B): B =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same concern here about adding a law that this violates. Maybe a == b implies toList(a) == toList(b)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're going to need to spend some more time to find something. That one won't work, because that way e.g
Either.Left(123) =!= Either.Left(-30) would imply List() =!= List()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it's the best solution but I worked around it, by only considering the positive case. I.e a == b implies toList(a) == toList(b) but not a != b implies toList(a) != toList(b)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I meant (which is why I didn’t say (a == b) == (a.toList == b.toList))

@johnynek
Copy link
Contributor

This looks good to me. One question: do you know if this test would actually have caught Map/Set problems? I guess it must have since small maps/sets are just tuples and created in the order added.

@LukaJCB
Copy link
Member Author

LukaJCB commented Oct 29, 2017

Yes I tested these on master and they failed for set/map.

@LukaJCB
Copy link
Member Author

LukaJCB commented Oct 29, 2017

Although to be fair, I ran into some problems because it might not actually generate a situation where the tests fail every time because it's rare that they generate two different collections with the same values but different orderings.

kailuowang
kailuowang previously approved these changes Oct 30, 2017
@kailuowang kailuowang dismissed their stale review October 30, 2017 14:19

realized that the Foldable test could be improved.

@kailuowang kailuowang changed the title Add SortedMap instances Add SortedMap and SortedSet instances Oct 30, 2017
@kailuowang
Copy link
Contributor

I couldn't think of a way to write the law so that will consistently fail on unordered data types either. Another option we have is to simply remove the orderedConsistency test and simply document the fact that Foldable only supports ordered F[_], for unordered F[_] use the new UnorderedFoldable and UnorderedTraverse, which we should probably do anyway.

@kailuowang kailuowang changed the title Add SortedMap and SortedSet instances Add SortedMap and SortedSet instances/Move Set and Map instances to Alleycats Oct 30, 2017
@kailuowang
Copy link
Contributor

thanks so much for pushing this through

@kailuowang kailuowang merged commit 1f0cba0 into typelevel:master Oct 30, 2017
@kailuowang kailuowang added this to the 1.0.0-RC1 milestone Oct 31, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Apply and Traverse for SortedMap
6 participants