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

Use simulacrum for typeclass boilerplate #806

Merged
merged 53 commits into from
Jan 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
2a6e52a
factor out a static inner method from #769 for better GC
aryairani Jan 5, 2016
81a24d9
Use Eval instead of Trampoline for State
ceedubs Jan 7, 2016
5f0324a
Add ScalaDoc example for foldK syntax
ceedubs Jan 7, 2016
d338150
Remove unused specialized State instance
ceedubs Jan 7, 2016
fc9a75b
Add ScalaDoc examples for Coproduct syntax
ceedubs Jan 7, 2016
2c6abdf
Add ScalaDoc for Either syntax
ceedubs Jan 8, 2016
05add1a
Add ScalaDoc for MonadCombine unite syntax
ceedubs Jan 8, 2016
0529841
Merge pull request #782 from ceedubs/state-eval
adelbertc Jan 8, 2016
8e92896
Add traverseU_ and sequenceU_
adelbertc Jan 10, 2016
a64cd76
Merge pull request #779 from refried/eval-defer-heap-safety
adelbertc Jan 10, 2016
5d87e70
Added scaladoc comments to all the function definitions in cats/arrow…
lukewyman Jan 11, 2016
e4ae734
Merge branch 'master' into topic/arrow-scaladoc
lukewyman Jan 12, 2016
815b8fb
Fix StreamingT.filter bug
ceedubs Jan 12, 2016
ebb92ba
Merge pull request #796 from adelbertc/foldable-unapply-syntax
ceedubs Jan 12, 2016
ceff342
Merge pull request #798 from ceedubs/streamingt-filter-bug
ceedubs Jan 12, 2016
61f148a
fixed a typo in scaladoc comment on cat/arrow/Arrow
lukewyman Jan 12, 2016
591555f
Merge pull request #797 from lukewyman/topic/arrow-scaladoc
ceedubs Jan 13, 2016
56dede8
Fix order of effects in FreeApplicative.foldMap
ceedubs Jan 13, 2016
3d2ffa9
Merge pull request #801 from ceedubs/freeapp-effect-order
non Jan 14, 2016
d8f33c8
Merge pull request #790 from ceedubs/monadcombine-syntax-docs
non Jan 14, 2016
a2253a1
Merge pull request #789 from ceedubs/either-syntax-docs
non Jan 14, 2016
f94b439
Merge pull request #784 from ceedubs/coproduct-syntax-docs
non Jan 14, 2016
0c0379e
Merge pull request #783 from ceedubs/foldK-example
non Jan 14, 2016
95f0897
Hide simulacrum dependency from the .pom
rklaehn Jan 14, 2016
1b9d2f1
Remove machinist dependency from cats-kernel
rklaehn Jan 14, 2016
289484c
Use @typeclass annotation for Eq typeclass
rklaehn Jan 14, 2016
b8c686a
Add typeclass annotation to Semigroup and Monoid
rklaehn Jan 14, 2016
66d485f
Add typeclass annotation to Group
rklaehn Jan 14, 2016
b33c9de
Add typeclass annotation to Order and PartialOrder
rklaehn Jan 14, 2016
0bba290
Fixed another compile error due to missing override
rklaehn Jan 14, 2016
8cbf29f
Remove reference to algebra in docs and adjust source paths
rklaehn Jan 14, 2016
b868421
Added stubs for documentation of remaining cats-kernel typeclasses
rklaehn Jan 14, 2016
45c0be4
Add XorT#valueOr
notxcain Jan 15, 2016
07d0cd1
Add test for XorT#valueOr
notxcain Jan 15, 2016
d4f896a
Prettify XorT#recoverWith
notxcain Jan 15, 2016
35e376b
Merge pull request #807 from notxcain/xort-valueor
ceedubs Jan 15, 2016
d6dce55
Merge pull request #808 from notxcain/prettify-recoverwith
non Jan 15, 2016
e0cd78c
Use "provided" instead of "compileonly" for simulacrum
rklaehn Jan 16, 2016
bfa8727
Remove "provided" dependencies
rklaehn Jan 16, 2016
312afa7
Add ApplicativeError
travisbrown Jan 18, 2016
15a5e8d
Merge pull request #812 from travisbrown/topic/applicative-error
adelbertc Jan 18, 2016
0864952
cats#813 - Adds CoflatMap type class to the Vector Instance
juanpedromoreno Jan 18, 2016
5d87506
cats#813 - Provides CoflatMap tests for VectorTests
juanpedromoreno Jan 18, 2016
4da172f
cats#813 - Removes non-necessary import
juanpedromoreno Jan 19, 2016
c20f6ed
cats#813 - Changes the coflatMap implementation in order to use ListB…
juanpedromoreno Jan 19, 2016
7ee5f2f
cats#813 - Addresses a code review comment, changing the coflatMap im…
juanpedromoreno Jan 19, 2016
4c714fd
Update list of authors
fthomas Jan 19, 2016
06eeb68
Merge pull request #818 from 47deg/juanpedromoreno-adds-coflatmap-typ…
fthomas Jan 19, 2016
f3c4eba
Upgrade to simulacrum 0.6.1, which makes type classes universal and s…
mpilquist Jan 20, 2016
722ce05
Merge pull request #819 from fthomas/topic/update-authors
milessabin Jan 20, 2016
d8e7e78
Merge pull request #820 from mpilquist/topic/simulacrum-upgrade
milessabin Jan 20, 2016
69ad4e4
Merge branch 'master' into topic/kernel
rklaehn Jan 20, 2016
87f2f3c
Fix merge conflict caused by the addition of mima to the kernel project.
rklaehn Jan 29, 2016
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
21 changes: 20 additions & 1 deletion AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,66 @@ possible:

* Adelbert Chang
* Alessandro Lacava
* Alexey Levan
* Alissa Pajer
* Alistair Johnson
* Amir Mohammad Saied
* Andrew Jones
* Antoine Comte
* Arya Irani
* Ash Pook
* Benjamin Thuillier
* Bobby
* Bobby Rauchenberg
* Brendan McAdams
* Cody Allen
* Colt Frederickson
* Dale Wijnand
* Dave Rostron
* David Allsopp
* David Gregory
* Denis Mikhaylov
* Derek Wickern
* Edmund Noble
* Erik LaBianca
* Erik Osheim
* Eugene Burmako
* Eugene Yokota
* Feynman Liang
* Frank S. Thomas
* Jean-Rémi Desjardins
* Jisoo Park
* Josh Marcus
* Julien Richard-Foy
* Julien Truffaut
* Kenji Yoshida
* Long Cao
* Luis Angel Vicente Sanchez
* Luke Wyman
* Marc Siegel
* Markus Hauck
* Matthias Lüneberg
* Michael Pilquist
* Mike Curry
* Miles Sabin
* Olli Helenius
* Owen Parry
* Pascal Voitot
* Paul Phillips
* Philip Wills
* Raúl Raja Martínez
* Rintcius Blok
* Rob Norris
* Romain Ruetschi
* Ross A. Baker
* Sarunas Valaskevicius
* Shunsuke Otani
* Sinisa Louc
* Stephen Judkins
* Stew O'Connor
* Sumedh Mungee
* Travis Brown
* Wedens
* Yosef Fertel
* Zach Abbott

We've tried to include everyone, but if you've made a contribution to
Expand Down
24 changes: 19 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,18 @@ lazy val commonSettings = Seq(
Resolver.sonatypeRepo("snapshots")
),
libraryDependencies ++= Seq(
"com.github.mpilquist" %%% "simulacrum" % "0.5.0",
"org.typelevel" %%% "machinist" % "0.4.1",
"com.github.mpilquist" %%% "simulacrum" % "0.6.1" % "provided",
compilerPlugin("org.scalamacros" %% "paradise" % "2.1.0-M5" cross CrossVersion.full),
compilerPlugin("org.spire-math" %% "kind-projector" % "0.6.3")
),
parallelExecution in Test := false,
scalacOptions in (Compile, doc) := (scalacOptions in (Compile, doc)).value.filter(_ != "-Xfatal-warnings")
) ++ warnUnusedImport

lazy val machinistDependencies = Seq(
libraryDependencies += "org.typelevel" %%% "machinist" % "0.4.1"
Copy link
Contributor

Choose a reason for hiding this comment

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

can this be compile only? I guess not or you would have done so.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note that machinistDependencies are only used in cats-core, not in cats-kernel. I don't know if this can be compile-only, but I did not want to mess with things other than cats-kernel for this PR.

cats-kernel does not have a dep on machinist for now. See pom.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ahh yes. Sorry. LGTM.

On Thu, Jan 14, 2016 at 2:23 PM, Rüdiger Klaehn notifications@github.com
wrote:

In build.sbt https://github.com/non/cats/pull/806#discussion_r49794859:

@@ -43,6 +44,10 @@ lazy val commonSettings = Seq(
scalacOptions in (Compile, doc) := (scalacOptions in (Compile, doc)).value.filter(_ != "-Xfatal-warnings")
) ++ warnUnusedImport

+lazy val machinistDependencies = Seq(

  • libraryDependencies += "org.typelevel" %%% "machinist" % "0.4.1"

Note that machinistDependencies are only used in cats-core, not in
cats-kernel. I don't know if this can be compile-only, but I did not want
to mess with things other than cats-kernel for this PR.

cats-kernel does not have a dep on machinist for now. See pom.


Reply to this email directly or view it on GitHub
https://github.com/non/cats/pull/806/files#r49794859.

P. Oscar Boykin, Ph.D. | http://twitter.com/posco | http://pobox.com/~boykin

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The entire picture isn't that clear to me either. It seems that a later version of simulacrum does use imp for summoning typeclasses instead of an @inline def apply method.

Copy link
Member

Choose a reason for hiding this comment

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

Right, the imp integration was just added in the last month or so. We could revert the imp integration to avoid the dependency and then tackle call-site inlining via macros ala imp and machinist once we start building typeclassic. I'm fine either way.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to no runtime deps, so reverting imp or using an older version would be my pref.

)

lazy val commonJsSettings = Seq(
scalaJSStage in Global := FastOptStage,
parallelExecution := false
Expand All @@ -56,7 +59,9 @@ lazy val commonJvmSettings = Seq(
// JVM settings. https://github.com/tkawachi/sbt-doctest/issues/52
) ++ catsDoctestSettings

lazy val catsSettings = buildSettings ++ commonSettings ++ publishSettings ++ scoverageSettings
lazy val kernelSettings = buildSettings ++ commonSettings ++ publishSettings ++ scoverageSettings

lazy val catsSettings = kernelSettings ++ machinistDependencies

lazy val scalacheckVersion = "1.12.5"

Expand Down Expand Up @@ -128,15 +133,24 @@ lazy val macros = crossProject.crossType(CrossType.Pure)
lazy val macrosJVM = macros.jvm
lazy val macrosJS = macros.js


lazy val kernel = crossProject.crossType(CrossType.Pure)
.settings(moduleName := "cats-kernel")
.settings(catsSettings:_*)
.settings(kernelSettings:_*)
.settings(mimaDefaultSettings:_*)
.settings(previousArtifacts := Set(
// TODO: Add cats-kernel artifacts as they are released, e.g.
// "org.spire-math" %% "cats-kernel" % "0.4.0"
))
.settings(pomPostProcess := { (node) =>
import scala.xml._
import scala.xml.transform._
def stripIf(f: Node => Boolean) = new RewriteRule {
override def transform(n: Node) =
if (f(n)) NodeSeq.Empty else n
}
val stripProvidedScope = stripIf { n => n.label == "dependency" && (n \ "scope").text == "provided" }
new RuleTransformer(stripProvidedScope).transform(node)(0)
})
.jsSettings(commonJsSettings:_*)
.jvmSettings(commonJvmSettings:_*)

Expand Down
81 changes: 81 additions & 0 deletions core/src/main/scala/cats/ApplicativeError.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cats

import cats.data.{Xor, XorT}

/**
* An applicative that also allows you to raise and or handle an error value.
*
* This type class allows one to abstract over error-handling applicatives.
*/
trait ApplicativeError[F[_], E] extends Applicative[F] {
/**
* Lift an error into the `F` context.
*/
def raiseError[A](e: E): F[A]

/**
* Handle any error, potentially recovering from it, by mapping it to an
* `F[A]` value.
*
* @see [[handleError]] to handle any error by simply mapping it to an `A`
* value instead of an `F[A]`.
*
* @see [[recoverWith]] to recover from only certain errors.
*/
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]

/**
* Handle any error, by mapping it to an `A` value.
*
* @see [[handleErrorWith]] to map to an `F[A]` value instead of simply an
* `A` value.
*
* @see [[recover]] to only recover from certain errors.
*/
def handleError[A](fa: F[A])(f: E => A): F[A] = handleErrorWith(fa)(f andThen pure)

/**
* Handle errors by turning them into [[cats.data.Xor.Left]] values.
*
* If there is no error, then an [[cats.data.Xor.Right]] value will be returned instead.
*
* All non-fatal errors should be handled by this method.
*/
def attempt[A](fa: F[A]): F[E Xor A] = handleErrorWith(
map(fa)(Xor.right[E, A])
)(e => pure(Xor.left(e)))

/**
* Similar to [[attempt]], but wraps the result in a [[cats.data.XorT]] for
* convenience.
*/
def attemptT[A](fa: F[A]): XorT[F, E, A] = XorT(attempt(fa))

/**
* Recover from certain errors by mapping them to an `A` value.
*
* @see [[handleError]] to handle any/all errors.
*
* @see [[recoverWith]] to recover from certain errors by mapping them to
* `F[A]` values.
*/
def recover[A](fa: F[A])(pf: PartialFunction[E, A]): F[A] =
handleErrorWith(fa)(e =>
(pf andThen pure) applyOrElse(e, raiseError))

/**
* Recover from certain errors by mapping them to an `F[A]` value.
*
* @see [[handleErrorWith]] to handle any/all errors.
*
* @see [[recover]] to recover from certain errors by mapping them to `A`
* values.
*/
def recoverWith[A](fa: F[A])(pf: PartialFunction[E, F[A]]): F[A] =
handleErrorWith(fa)(e =>
pf applyOrElse(e, raiseError))
}

object ApplicativeError {
def apply[F[_], E](implicit F: ApplicativeError[F, E]): ApplicativeError[F, E] = F
}
29 changes: 15 additions & 14 deletions core/src/main/scala/cats/Eval.scala
Original file line number Diff line number Diff line change
Expand Up @@ -223,20 +223,21 @@ object Eval extends EvalInstances {
*/
sealed abstract class Call[A](val thunk: () => Eval[A]) extends Eval[A] {
def memoize: Eval[A] = new Later(() => value)
def value: A = {
def loop(fa: Eval[A]): Eval[A] = fa match {
case call: Eval.Call[A] =>
loop(call.thunk())
case compute: Eval.Compute[A] =>
new Eval.Compute[A] {
type Start = compute.Start
val start: () => Eval[Start] = () => compute.start()
val run: Start => Eval[A] = s => loop(compute.run(s))
}
case other => other
}

loop(this).value
def value: A = Call.loop(this).value
}

object Call {
/** Collapse the call stack for eager evaluations */
private def loop[A](fa: Eval[A]): Eval[A] = fa match {
case call: Eval.Call[A] =>
loop(call.thunk())
case compute: Eval.Compute[A] =>
new Eval.Compute[A] {
type Start = compute.Start
val start: () => Eval[Start] = () => compute.start()
val run: Start => Eval[A] = s => loop(compute.run(s))
}
case other => other
}
}

Expand Down
51 changes: 49 additions & 2 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import simulacrum.typeclass
*
* See: [[http://www.cs.nott.ac.uk/~pszgmh/fold.pdf A tutorial on the universality and expressiveness of fold]]
*/
@typeclass trait Foldable[F[_]] extends Serializable { self =>
@typeclass trait Foldable[F[_]] { self =>

/**
* Left associative fold on 'F' using the function 'f'.
Expand Down Expand Up @@ -107,6 +107,31 @@ import simulacrum.typeclass
G.map2(acc, f(a)) { (_, _) => () }
}

/**
* Behaves like traverse_, but uses [[Unapply]] to find the
* [[Applicative]] instance for `G` - used when `G` is a
* type constructor with two or more parameters such as [[cats.data.Xor]]
*
* {{{
* scala> import cats.data.Xor
* scala> import cats.std.list._
* scala> def parseInt(s: String): Xor[String, Int] =
* | try { Xor.Right(s.toInt) }
* | catch { case _: NumberFormatException => Xor.Left("boo") }
* scala> val F = Foldable[List]
* scala> F.traverseU_(List("333", "444"))(parseInt)
* res0: Xor[String, Unit] = Right(())
* scala> F.traverseU_(List("333", "zzz"))(parseInt)
* res1: Xor[String, Unit] = Left(boo)
* }}}
*
* Note that using `traverse_` instead of `traverseU_` would not compile without
* explicitly passing in the type parameters - the type checker has trouble
* inferring the appropriate instance.
*/
def traverseU_[A, GB](fa: F[A])(f: A => GB)(implicit U: Unapply[Applicative, GB]): U.M[Unit] =
traverse_(fa)(f.andThen(U.subst))(U.TC)

/**
* Sequence `F[G[A]]` using `Applicative[G]`.
*
Expand All @@ -125,9 +150,31 @@ import simulacrum.typeclass
* res1: Option[Unit] = None
* }}}
*/
def sequence_[G[_]: Applicative, A, B](fga: F[G[A]]): G[Unit] =
def sequence_[G[_]: Applicative, A](fga: F[G[A]]): G[Unit] =
traverse_(fga)(identity)

/**
* Behaves like sequence_, but uses [[Unapply]] to find the
* [[Applicative]] instance for `G` - used when `G` is a
* type constructor with two or more parameters such as [[cats.data.Xor]]
*
* {{{
* scala> import cats.data.Xor
* scala> import cats.std.list._
* scala> val F = Foldable[List]
* scala> F.sequenceU_(List(Xor.right[String, Int](333), Xor.Right(444)))
* res0: Xor[String, Unit] = Right(())
* scala> F.sequenceU_(List(Xor.right[String, Int](333), Xor.Left("boo")))
* res1: Xor[String, Unit] = Left(boo)
* }}}
*
* Note that using `sequence_` instead of `sequenceU_` would not compile without
* explicitly passing in the type parameters - the type checker has trouble
* inferring the appropriate instance.
*/
def sequenceU_[GA](fa: F[GA])(implicit U: Unapply[Applicative, GA]): U.M[Unit] =
traverseU_(fa)(identity)

/**
* Fold implemented using the given `MonoidK[G]` instance.
*
Expand Down
69 changes: 1 addition & 68 deletions core/src/main/scala/cats/MonadError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,74 +7,7 @@ import cats.data.{Xor, XorT}
*
* This type class allows one to abstract over error-handling monads.
*/
trait MonadError[F[_], E] extends Monad[F] {
/**
* Lift an error into the `F` context.
*/
def raiseError[A](e: E): F[A]

/**
* Handle any error, potentially recovering from it, by mapping it to an
* `F[A]` value.
*
* @see [[handleError]] to handle any error by simply mapping it to an `A`
* value instead of an `F[A]`.
*
* @see [[recoverWith]] to recover from only certain errors.
*/
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]

/**
* Handle any error, by mapping it to an `A` value.
*
* @see [[handleErrorWith]] to map to an `F[A]` value instead of simply an
* `A` value.
*
* @see [[recover]] to only recover from certain errors.
*/
def handleError[A](fa: F[A])(f: E => A): F[A] = handleErrorWith(fa)(f andThen pure)

/**
* Handle errors by turning them into [[cats.data.Xor.Left]] values.
*
* If there is no error, then an [[cats.data.Xor.Right]] value will be returned instead.
*
* All non-fatal errors should be handled by this method.
*/
def attempt[A](fa: F[A]): F[E Xor A] = handleErrorWith(
map(fa)(Xor.right[E, A])
)(e => pure(Xor.left(e)))

/**
* Similar to [[attempt]], but wraps the result in a [[cats.data.XorT]] for
* convenience.
*/
def attemptT[A](fa: F[A]): XorT[F, E, A] = XorT(attempt(fa))

/**
* Recover from certain errors by mapping them to an `A` value.
*
* @see [[handleError]] to handle any/all errors.
*
* @see [[recoverWith]] to recover from certain errors by mapping them to
* `F[A]` values.
*/
def recover[A](fa: F[A])(pf: PartialFunction[E, A]): F[A] =
handleErrorWith(fa)(e =>
(pf andThen pure) applyOrElse(e, raiseError))

/**
* Recover from certain errors by mapping them to an `F[A]` value.
*
* @see [[handleErrorWith]] to handle any/all errors.
*
* @see [[recover]] to recover from certain errors by mapping them to `A`
* values.
*/
def recoverWith[A](fa: F[A])(pf: PartialFunction[E, F[A]]): F[A] =
handleErrorWith(fa)(e =>
pf applyOrElse(e, raiseError))
}
trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F]

object MonadError {
def apply[F[_], E](implicit F: MonadError[F, E]): MonadError[F, E] = F
Expand Down
Loading