Skip to content

Commit 89c5217

Browse files
author
Oleg Nizhnik
committed
renamed Eq alias
added some tests
1 parent d3dd7d0 commit 89c5217

File tree

9 files changed

+187
-19
lines changed

9 files changed

+187
-19
lines changed

Diff for: build.sbt

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
name := "fpspeedrun"
22

3-
version := "0.1"
3+
version := "mainrun-3"
44

55
scalaVersion := "2.12.6"
66

7-
scalacOptions += "-Ypartial-unification"
8-
97
libraryDependencies += "org.typelevel" %% "cats-core" % "1.1.0"
108
libraryDependencies += "org.typelevel" %% "cats-effect" % "1.0.0-RC2"
119
libraryDependencies += "com.github.mpilquist" %% "simulacrum" % "0.12.0"
1210

11+
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % "test"
12+
libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.14.0" % "test"
13+
1314
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7")
14-
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
15+
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.patch)
16+
17+
1518

Diff for: compiler.sbt

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//source https://tpolecat.github.io/2017/04/25/scalac-flags.html
2+
3+
scalacOptions ++= Seq(
4+
"-deprecation", // Emit warning and location for usages of deprecated APIs.
5+
"-encoding", "utf-8", // Specify character encoding used by source files.
6+
"-explaintypes", // Explain type errors in more detail.
7+
"-feature", // Emit warning and location for usages of features that should be imported explicitly.
8+
"-language:existentials", // Existential types (besides wildcard types) can be written and inferred
9+
"-language:experimental.macros", // Allow macro definition (besides implementation and application)
10+
"-language:higherKinds", // Allow higher-kinded types
11+
"-language:implicitConversions", // Allow definition of implicit functions called views
12+
"-unchecked", // Enable additional warnings where generated code depends on assumptions.
13+
"-Xcheckinit", // Wrap field accessors to throw an exception on uninitialized access.
14+
// too brute for students
15+
// "-Xfatal-warnings", // Fail the compilation if there are any warnings.
16+
"-Xfuture", // Turn on future language features.
17+
"-Xlint:adapted-args", // Warn if an argument list is modified to match the receiver.
18+
"-Xlint:by-name-right-associative", // By-name parameter of right associative operator.
19+
"-Xlint:constant", // Evaluation of a constant arithmetic expression results in an error.
20+
"-Xlint:delayedinit-select", // Selecting member of DelayedInit.
21+
"-Xlint:doc-detached", // A Scaladoc comment appears to be detached from its element.
22+
"-Xlint:inaccessible", // Warn about inaccessible types in method signatures.
23+
"-Xlint:infer-any", // Warn when a type argument is inferred to be `Any`.
24+
"-Xlint:missing-interpolator", // A string literal appears to be missing an interpolator id.
25+
"-Xlint:nullary-override", // Warn when non-nullary `def f()' overrides nullary `def f'.
26+
"-Xlint:nullary-unit", // Warn when nullary methods return Unit.
27+
"-Xlint:option-implicit", // Option.apply used implicit view.
28+
"-Xlint:package-object-classes", // Class or object defined in package object.
29+
"-Xlint:poly-implicit-overload", // Parameterized overloaded implicit methods are not visible as view bounds.
30+
"-Xlint:private-shadow", // A private field (or class parameter) shadows a superclass field.
31+
"-Xlint:stars-align", // Pattern sequence wildcard must align with sequence component.
32+
"-Xlint:type-parameter-shadow", // A local type parameter shadows a type already in scope.
33+
"-Xlint:unsound-match", // Pattern match may not be typesafe.
34+
"-Yno-adapted-args", // Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver.
35+
"-Ypartial-unification", // Enable partial unification in type constructor inference
36+
"-Ywarn-dead-code", // Warn when dead code is identified.
37+
"-Ywarn-extra-implicit", // Warn when more than one implicit parameter section is defined.
38+
"-Ywarn-inaccessible", // Warn about inaccessible types in method signatures.
39+
"-Ywarn-infer-any", // Warn when a type argument is inferred to be `Any`.
40+
"-Ywarn-nullary-override", // Warn when non-nullary `def f()' overrides nullary `def f'.
41+
"-Ywarn-nullary-unit", // Warn when nullary methods return Unit.
42+
"-Ywarn-numeric-widen", // Warn when numerics are widened.
43+
"-Ywarn-unused:implicits", // Warn if an implicit parameter is unused.
44+
"-Ywarn-unused:imports", // Warn if an import selector is not referenced.
45+
"-Ywarn-unused:locals", // Warn if a local definition is unused.
46+
"-Ywarn-unused:params", // Warn if a value parameter is unused.
47+
"-Ywarn-unused:patvars", // Warn if a variable bound in a pattern is unused.
48+
"-Ywarn-unused:privates", // Warn if a private member is unused.
49+
"-Ywarn-value-discard", // Warn when non-Unit expression results are unused.
50+
)

Diff for: src/main/scala/fpspeedrun/Eq.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ trait Eq[T] {
88
@op("===", alias = true)
99
def equal(x: T, y: T): Boolean
1010

11-
@op("!==")
11+
@op("=/=")
1212
def notEqual(x: T, y: T): Boolean = ! equal(x, y)
1313
}
1414

Diff for: src/main/scala/fpspeedrun/Iso.scala

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ object Iso {
1111
def value: T
1212
}
1313

14-
trait WrapperIso[T, F[x] <: Wrapper[x]] extends Iso[T, F[T]] {
15-
override def unwrap(b: F[T]): T = b.value
14+
trait WrapperCompanion[F[x] <: Wrapper[x]]{
15+
def apply[T](x: T): F[T]
16+
implicit def wrapperIso[T]: Iso[T, F[T]] = new Iso[T, F[T]]{
17+
override def wrap(a: T): F[T] = apply(a)
18+
override def unwrap(b: F[T]): T = b.value
19+
}
1620
}
1721
}
1822

Diff for: src/main/scala/fpspeedrun/Semigroup.scala

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package fpspeedrun
2-
import fpspeedrun.Iso.{Wrapper, WrapperIso}
2+
import fpspeedrun.Iso.{Wrapper, WrapperCompanion}
33
import simulacrum.{op, typeclass}
44
import syntax.num._
55

6-
76
@typeclass
87
trait Semigroup[T] {
98
@op("|+|", alias = true)
@@ -12,33 +11,28 @@ trait Semigroup[T] {
1211

1312
object Semigroup extends StdSemigroupInstances
1413

15-
1614
final case class Sum[T](value: T) extends AnyVal with Wrapper[T]
1715

18-
object Sum{
16+
object Sum extends WrapperCompanion[Sum] {
1917
implicit def sumSemigroup[T: Num]: Semigroup[Sum[T]] = (x, y) => Sum(x.value + y.value)
20-
implicit def iso[A]: WrapperIso[A, Sum] = Sum(_)
2118
}
2219

2320
final case class Prod[T](value: T) extends AnyVal with Wrapper[T]
2421

25-
object Prod {
22+
object Prod extends WrapperCompanion[Prod] {
2623
implicit def prodSemigroup[T: Num]: Semigroup[Prod[T]] = (x, y) => Prod(x.value * y.value)
27-
implicit def iso[A]: WrapperIso[A, Prod] = Prod(_)
2824
}
2925

3026
final case class First[T](value: T) extends AnyVal with Wrapper[T]
3127

32-
object First {
28+
object First extends WrapperCompanion[First] {
3329
implicit def firstSemigroup[T]: Semigroup[First[T]] = (x, _) => x
34-
implicit def iso[A]: WrapperIso[A, First] = First(_)
3530
}
3631

3732
final case class Last[T](value: T) extends AnyVal with Wrapper[T]
3833

39-
object Last {
34+
object Last extends WrapperCompanion[Last] {
4035
implicit def lastSemigroup[T]: Semigroup[Last[T]] = (_, y) => y
41-
implicit def iso[A]: WrapperIso[A, Last] = Last(_)
4236
}
4337

4438
trait StdSemigroupInstances extends StdMonoidInstances[Semigroup]

Diff for: src/main/scala/fpspeedrun/syntax/package.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package fpspeedrun.syntax
22
import fpspeedrun._
33

4-
54
object eq extends Eq.ToEqOps
65

76
object ord extends Ord.ToOrdOps
@@ -21,6 +20,7 @@ object frac extends Frac.ToFracOps
2120
object ratio {
2221
implicit class RatioOps[T](val x: T) extends AnyVal {
2322
def \\(y: T)(implicit int: Integ[T]): Ratio[T] = Ratio.make(x, y)
23+
def toRatio(implicit int: Integ[T]): Ratio[T] = Ratio.make(x, int.one)
2424
}
2525
}
2626

Diff for: src/test/scala/fpspeedrun/RatioGenerators.scala

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package fpspeedrun
2+
import org.scalacheck.Arbitrary
3+
import Arbitrary.arbitrary
4+
import syntax.ratio._
5+
6+
trait RatioGenerators {
7+
implicit def arbitraryRatio[T: Arbitrary : Integ]: Arbitrary[Ratio[T]] =
8+
Arbitrary(for {
9+
numerator <- arbitrary[T]
10+
denominator <- arbitrary[T]
11+
} yield numerator \\ denominator)
12+
}

Diff for: src/test/scala/fpspeedrun/SemigroupSuite.scala

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package fpspeedrun
2+
3+
import org.scalatest.{Matchers, WordSpec}
4+
import org.scalatest.prop.PropertyChecks
5+
import syntax.semigroup._
6+
import syntax.ratio._
7+
import syntax.num._
8+
9+
class SemigroupSuite extends WordSpec with Matchers with PropertyChecks {
10+
"list optional reducing" when {
11+
"reducing strings" should {
12+
"reduce empty list" in {
13+
List.empty[String].reduceOpt shouldBe None
14+
}
15+
"reduce non empty list" in {
16+
forAll((x : String, xs: List[String]) =>
17+
(x :: xs).reduceOpt shouldBe Some((x :: xs).mkString))
18+
}
19+
}
20+
21+
"reducing ints" when {
22+
"adding" should {
23+
"reduce empty list" in {
24+
List.empty[Int].reduceOptVia[Sum] shouldBe None
25+
}
26+
"reduce non-empty list" in {
27+
forAll((x: Int, xs: List[Int]) =>
28+
(x :: xs).reduceOptVia[Sum] shouldBe Some(x + xs.sum))
29+
}
30+
}
31+
32+
"multiplying" should {
33+
"reduce empty list" in {
34+
List.empty[Int].reduceOptVia[Prod] shouldBe None
35+
}
36+
"reduce non-empty list" in {
37+
forAll((x: Int, xs: List[Int]) =>
38+
(x :: xs).reduceOptVia[Prod] shouldBe Some(x * xs.product))
39+
}
40+
}
41+
42+
"searching leftmost" should {
43+
"reduce empty list" in {
44+
List.empty[Int].reduceOptVia[First] shouldBe None
45+
}
46+
"reduce non-empty list" in {
47+
forAll((x: Int, xs: List[Int]) =>
48+
(x :: xs).reduceOptVia[First] shouldBe Some(x))
49+
}
50+
}
51+
52+
"searching rightmost" should {
53+
"reduce empty list" in {
54+
List.empty[Int].reduceOptVia[Last] shouldBe None
55+
}
56+
"reduce non-empty list" in {
57+
forAll((x: Int, xs: List[Int]) =>
58+
(x :: xs).reduceOptVia[Last] shouldBe Some((x :: xs).last))
59+
}
60+
}
61+
}
62+
63+
"reducing ratios" when {
64+
"fractions are integers" should {
65+
"sum numerators" in {
66+
forAll((xs: List[Int]) =>
67+
xs.map(_.toRatio).reduceOptVia[Sum] shouldBe xs.reduceOption(_ + _).map(_.toRatio)
68+
)
69+
}
70+
71+
"multiply numerators" in {
72+
forAll((xs: List[Int]) =>
73+
xs.map(_.toRatio).reduceOptVia[Prod] shouldBe xs.reduceOption(_ * _).map(_.toRatio)
74+
)
75+
}
76+
}
77+
"facing arbitrary fractions" should {
78+
"sum fractions" in {
79+
forAll((xs: List[Ratio[BigInt]]) =>
80+
xs.reduceOptVia[Sum] shouldBe xs.reduceOption(_ + _)
81+
)
82+
}
83+
84+
"multiply fractions" in {
85+
forAll((xs: List[Ratio[BigInt]]) =>
86+
xs.reduceOptVia[Prod] shouldBe xs.reduceOption(_ * _)
87+
)
88+
}
89+
90+
"find leftmost fraction" in {
91+
forAll((xs: List[Ratio[BigInt]]) =>
92+
xs.reduceOptVia[First] shouldBe xs.headOption
93+
)
94+
}
95+
96+
"find rightmost fraction" in {
97+
forAll((xs: List[Ratio[BigInt]]) =>
98+
xs.reduceOptVia[Last] shouldBe xs.lastOption
99+
)
100+
}
101+
}
102+
}
103+
}
104+
}

Diff for: src/test/scala/fpspeedrun/package.scala

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package object fpspeedrun extends RatioGenerators

0 commit comments

Comments
 (0)