Skip to content

Commit

Permalink
Add Invariant and Semigroupal typeclasses for ViewF
Browse files Browse the repository at this point in the history
  • Loading branch information
hugo-vrijswijk committed Oct 25, 2023
1 parent e07e0b1 commit 8239eb9
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 0 deletions.
10 changes: 10 additions & 0 deletions shared/src/main/scala/crystal/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ package crystal
import cats.Applicative
import cats.Eq
import cats.FlatMap
import cats.Invariant
import cats.Monad
import cats.Semigroupal
import cats.effect.Ref
import cats.syntax.all.*

Expand Down Expand Up @@ -36,3 +38,11 @@ object throwable {
(x ne null) == (y ne null)
}
}

given [F[_]: Monad]: Semigroupal[ViewF[F, *]] with
def product[A, B](fa: ViewF[F, A], fb: ViewF[F, B]): ViewF[F, (A, B)] =
ViewF.apply(fa.get -> fb.get, (f, cb) => cb(f(fa.get, fb.get)))

given [F[_]: Monad]: Invariant[ViewF[F, *]] with
def imap[A, B](fa: ViewF[F, A])(f: A => B)(g: B => A): ViewF[F, B] =
fa.zoom(f)(mod => a => g(mod(f(a))))
1 change: 1 addition & 0 deletions shared/src/main/scala/crystal/syntax.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ trait syntax {
def toPot: Pot[A] = Pot.fromTry[A](a)
@targetName("tryToPotOption")
def toPotOption: PotOption[A] = PotOption.fromTry(a)

}

object syntax extends syntax
28 changes: 28 additions & 0 deletions shared/src/test/scala/crystal/ViewFLawsSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2016-2023 Association of Universities for Research in Astronomy, Inc. (AURA)
// For license information see LICENSE or https://opensource.org/licenses/BSD-3-Clause

package crystal

import cats.Eq
import cats.Id
import cats.Invariant
import cats.laws.discipline.InvariantTests
import cats.laws.discipline.SemigroupalTests
import munit.DisciplineSuite

import arbitraries.given

class ViewFLawsSpec extends DisciplineSuite {

private given viewEq[A: Eq]: Eq[ViewF[Id, A]] = Eq.by(_.get)

checkAll(
"ViewF[Int].InvariantLaws",
InvariantTests[ViewF[Id, *]].invariant[Int, Int, String]
)

checkAll(
"ViewF[Int].SemigroupalLaws",
SemigroupalTests[ViewF[Id, *]].semigroupal[Int, Int, String]
)
}
5 changes: 5 additions & 0 deletions shared/src/test/scala/crystal/arbitraries.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

package crystal

import cats.Id
import org.scalacheck.*

import scala.annotation.targetName
Expand Down Expand Up @@ -33,6 +34,10 @@ object arbitraries {
)
)

given viewFArb[A: Arbitrary]: Arbitrary[ViewF[Id, A]] = Arbitrary(
arbitrary[A].map(a => ViewF.apply[Id, A](a, (f, cb) => cb(f(a))))
)

@targetName("potOptionFnArbitrary")
given [A](using fArb: Arbitrary[A => A]): Arbitrary[PotOption[A] => PotOption[A]] =
Arbitrary(arbitrary[A => A].map(f => _.map(f)))
Expand Down

0 comments on commit 8239eb9

Please sign in to comment.