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 count as syntax to UnorderedFoldable #2520

Merged
merged 4 commits into from
Sep 25, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/src/main/scala/cats/implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ object implicits
with syntax.AllSyntaxBinCompat0
with syntax.AllSyntaxBinCompat1
with syntax.AllSyntaxBinCompat2
with syntax.AllSyntaxBinCompat3
with instances.AllInstances
with instances.AllInstancesBinCompat0
with instances.AllInstancesBinCompat1
4 changes: 4 additions & 0 deletions core/src/main/scala/cats/syntax/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ abstract class AllSyntaxBinCompat
with AllSyntaxBinCompat0
with AllSyntaxBinCompat1
with AllSyntaxBinCompat2
with AllSyntaxBinCompat3

trait AllSyntax
extends AlternativeSyntax
Expand Down Expand Up @@ -77,3 +78,6 @@ trait AllSyntaxBinCompat2
with EitherSyntaxBinCompat0
with ListSyntaxBinCompat0
with ValidatedSyntaxBincompat0

trait AllSyntaxBinCompat3
extends UnorderedFoldableSyntax
33 changes: 33 additions & 0 deletions core/src/main/scala/cats/syntax/unorderedFoldable.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package cats
package syntax

import cats.instances.long._

trait UnorderedFoldableSyntax extends UnorderedFoldable.ToUnorderedFoldableOps {
implicit final def catsSyntaxUnorderedFoldableOps[F[_]: UnorderedFoldable, A](fa: F[A]): UnorderedFoldableOps[F, A] =
new UnorderedFoldableOps[F, A](fa)
}

final class UnorderedFoldableOps[F[_], A](val fa: F[A]) extends AnyVal {
/**
* Count the number of elements in the structure that satisfy the given predicate.
*
* For example:
* {{{
* scala> import cats.implicits._
* scala> val set1 = Set[String]()
* scala> set1.count_(_.length > 0)
* res0: Long = 0
*
* scala> val set2 = Set("hello", "world", "!")
* scala> set2.count_(_.length > 1)
* res1: Long = 2
*
* scala> val set3 = Set(41, 32, 23)
* scala> set3.count_(_ % 2 == 0)
* res2: Long = 1
* }}}
*/
def count_(p: A => Boolean)(implicit F: UnorderedFoldable[F]): Long =
Copy link
Member

Choose a reason for hiding this comment

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

Maybe it'd be better to have count defined in the UnorderedFoldable trait itself, and only call count here? Otherwise you can only use it with the syntax implicits, and not just F.count

Copy link
Member

Choose a reason for hiding this comment

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

You can't do that if you want to maintain binary compat.

Copy link
Member

Choose a reason for hiding this comment

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

Aww damn :( the encoding of traits strikes again

Copy link
Member

Choose a reason for hiding this comment

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

we should be able to define extensions for typeclass instances, like:

implicit class UFOps[F[_]](val instance: UnorderedFoldable[F]) extends AnyVal {
  def count(...)
}

F.unorderedFoldMap(fa)(a => if (p(a)) 1L else 0L)
}
4 changes: 2 additions & 2 deletions testkit/src/main/scala/cats/tests/CatsSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package tests

import catalysts.Platform
import cats.instances.{AllInstances, AllInstancesBinCompat0, AllInstancesBinCompat1}
import cats.syntax.{AllSyntax, AllSyntaxBinCompat0, AllSyntaxBinCompat1, AllSyntaxBinCompat2, EqOps}
import cats.syntax.{AllSyntax, AllSyntaxBinCompat0, AllSyntaxBinCompat1, AllSyntaxBinCompat2, AllSyntaxBinCompat3, EqOps}
import org.scalactic.anyvals.{PosInt, PosZDouble, PosZInt}
import org.scalatest.{FunSuite, FunSuiteLike, Matchers}
import org.scalatest.prop.{Configuration, GeneratorDrivenPropertyChecks}
Expand Down Expand Up @@ -35,7 +35,7 @@ trait CatsSuite extends FunSuite
with TestSettings
with AllInstances with AllInstancesBinCompat0 with AllInstancesBinCompat1
with AllSyntax with AllSyntaxBinCompat0 with AllSyntaxBinCompat1
with AllSyntaxBinCompat2
with AllSyntaxBinCompat2 with AllSyntaxBinCompat3
with StrictCatsEquality { self: FunSuiteLike =>

implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
Expand Down
26 changes: 26 additions & 0 deletions tests/src/test/scala/cats/tests/UnorderedFoldableSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cats
package tests

import org.scalatest.prop.PropertyChecks
import org.scalacheck.Arbitrary
import cats.instances.all._

abstract class UnorderedFoldableSuite[F[_]: UnorderedFoldable](name: String)(
implicit ArbFString: Arbitrary[F[String]]) extends CatsSuite with PropertyChecks {

def iterator[T](fa: F[T]): Iterator[T]

test(s"UnorderedFoldable[$name].count") {
forAll { (fa: F[String], p: String => Boolean) =>
fa.count_(p) === iterator(fa).count(p).toLong
}
}
}

class UnorderedFoldableSetSuite extends UnorderedFoldableSuite[Set]("set") {
def iterator[T](set: Set[T]): Iterator[T] = set.iterator
}

class UnorderedFoldableMapSuite extends UnorderedFoldableSuite[Map[String, ?]]("map") {
def iterator[T](map: Map[String, T]): Iterator[T] = map.valuesIterator
}