From ecad47acb7543ba47b876ca24a956a873c158851 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Wed, 2 Dec 2015 00:19:21 -0800 Subject: [PATCH] added :silent modifier here and there --- docs/src/main/tut/apply.md | 5 ++- docs/src/main/tut/const.md | 26 +++++++-------- docs/src/main/tut/foldable.md | 12 +++++-- docs/src/main/tut/functor.md | 12 +++---- docs/src/main/tut/kleisli.md | 29 +++++++++-------- docs/src/main/tut/monad.md | 6 ++-- docs/src/main/tut/monoid.md | 38 ++++++++++++++-------- docs/src/main/tut/semigroup.md | 31 ++++++++++++------ docs/src/main/tut/semigroupk.md | 20 +++++++++--- docs/src/main/tut/traverse.md | 55 ++++++++++++++++++++------------ docs/src/main/tut/typeclasses.md | 20 +++++++----- docs/src/main/tut/validated.md | 39 ++++++++++++++-------- docs/src/main/tut/xor.md | 22 ++++++------- 13 files changed, 193 insertions(+), 122 deletions(-) diff --git a/docs/src/main/tut/apply.md b/docs/src/main/tut/apply.md index 4650c3b326..3c56ae6b60 100644 --- a/docs/src/main/tut/apply.md +++ b/docs/src/main/tut/apply.md @@ -14,8 +14,9 @@ a context can be `Option`, `List` or `Future` for example). However, the difference between `ap` and `map` is that for `ap` the function that takes care of the transformation is of type `F[A => B]`, whereas for `map` it is `A => B`: -```tut +```tut:silent import cats._ + val intToString: Int => String = _.toString val double: Int => Int = _ * 2 val addTwo: Int => Int = _ + 2 @@ -133,8 +134,6 @@ f2(Some(1), Some(2), Some(3)) All instances created by `|@|` have `map`, `ap`, and `tupled` methods of the appropriate arity: ```tut -import cats.syntax.apply._ - val option2 = Option(1) |@| Option(2) val option3 = option2 |@| Option.empty[Int] diff --git a/docs/src/main/tut/const.md b/docs/src/main/tut/const.md index 3ccd9aee7d..d57e00e3b0 100644 --- a/docs/src/main/tut/const.md +++ b/docs/src/main/tut/const.md @@ -13,13 +13,13 @@ have its uses, which serve as a nice example of the consistency and elegance of ## Thinking about `Const` The `Const` data type can be thought of similarly to the `const` function, but as a data type. -```tut +```tut:silent def const[A, B](a: A)(b: => B): A = a ``` The `const` function takes two arguments and simply returns the first argument, ignoring the second. -```scala +```tut:silent final case class Const[A, B](getConst: A) ``` @@ -44,7 +44,7 @@ to use a lens. A lens can be thought of as a first class getter/setter. A `Lens[S, A]` is a data type that knows how to get an `A` out of an `S`, or set an `A` in an `S`. -```tut +```tut:silent trait Lens[S, A] { def get(s: S): A @@ -58,7 +58,7 @@ trait Lens[S, A] { It can be useful to have effectful modifications as well - perhaps our modification can fail (`Option`) or can return several values (`List`). -```tut +```tut:silent trait Lens[S, A] { def get(s: S): A @@ -78,7 +78,7 @@ trait Lens[S, A] { Note that both `modifyOption` and `modifyList` share the *exact* same implementation. If we look closely, the only thing we need is a `map` operation on the data type. Being good functional programmers, we abstract. -```tut +```tut:silent import cats.Functor import cats.syntax.functor._ @@ -99,7 +99,7 @@ We can redefine `modify` in terms of `modifyF` by using `cats.Id`. We can also t that simply ignores the current value. Due to these modifications however, we must leave `modifyF` abstract since having it defined in terms of `set` would lead to infinite circular calls. -```tut +```tut:silent import cats.Id trait Lens[S, A] { @@ -134,7 +134,7 @@ is to take an `A` and return it right back (lifted into `Const`). Before we plug and play however, note that `modifyF` has a `Functor` constraint on `F[_]`. This means we need to define a `Functor` instance for `Const`, where the first type parameter is fixed. -```tut +```tut:silent import cats.data.Const implicit def constFunctor[X]: Functor[Const[X, ?]] = @@ -147,7 +147,7 @@ implicit def constFunctor[X]: Functor[Const[X, ?]] = Now that that's taken care of, let's substitute and see what happens. -```tut +```tut:silent trait Lens[S, A] { def modifyF[F[_] : Functor](s: S)(f: A => F[A]): F[S] @@ -174,7 +174,7 @@ In the popular [The Essence of the Iterator Pattern](https://www.cs.ox.ac.uk/jer paper, Jeremy Gibbons and Bruno C. d. S. Oliveria describe a functional approach to iterating over a collection of data. Among the abstractions presented are `Foldable` and `Traverse`, replicated below (also available in Cats). -```tut +```tut:silent import cats.{Applicative, Monoid} trait Foldable[F[_]] { @@ -194,7 +194,7 @@ These two type classes seem unrelated - one reduces a collection down to a singl a collection with an effectful function, collecting results. It may be surprising to see that in fact `Traverse` subsumes `Foldable`. -```tut +```tut:silent trait Traverse[F[_]] extends Foldable[F] { def traverse[G[_] : Applicative, A, X](fa: F[A])(f: A => G[X]): G[F[X]] @@ -211,7 +211,7 @@ However, if we imagine `G[_]` to be a sort of type-level constant function, wher `F[X]` is the value we want to ignore, we treat it as the second type parameter and hence, leave it as the free one. -```tut +```tut:silent import cats.data.Const implicit def constApplicative[Z]: Applicative[Const[Z, ?]] = @@ -235,7 +235,7 @@ should try to do something more useful. This suggests composition of `Z`s, which So now we need a constant `Z` value, and a binary function that takes two `Z`s and produces a `Z`. Sound familiar? We want `Z` to have a `Monoid` instance! -```tut +```tut:silent implicit def constApplicative[Z : Monoid]: Applicative[Const[Z, ?]] = new Applicative[Const[Z, ?]] { def pure[A](a: A): Const[Z, A] = Const(Monoid[Z].empty) @@ -261,7 +261,7 @@ So to summarize, what we want is a function `A => Const[B, Nothing]`, and we hav that `Const[B, Z]` (for any `Z`) is the moral equivalent of just `B`, so `A => Const[B, Nothing]` is equivalent to `A => B`, which is exactly what we have, we just need to wrap it. -```tut +```tut:silent trait Traverse[F[_]] extends Foldable[F] { def traverse[G[_] : Applicative, A, X](fa: F[A])(f: A => G[X]): G[F[X]] diff --git a/docs/src/main/tut/foldable.md b/docs/src/main/tut/foldable.md index e707b21666..34ff817440 100644 --- a/docs/src/main/tut/foldable.md +++ b/docs/src/main/tut/foldable.md @@ -23,10 +23,16 @@ used by the associated `Foldable[_]` instance. These form the basis for many other operations, see also: [A tutorial on the universality and expressiveness of fold](https://www.cs.nott.ac.uk/~gmh/fold.pdf) -```tut +First some standard imports. + +```tut:silent import cats._ import cats.std.all._ +``` + +And examples. +```tut Foldable[List].fold(List("a", "b", "c")) Foldable[List].foldMap(List(1, 2, 4))(_.toString) Foldable[List].foldK(List(List(1,2,3), List(2,3,4))) @@ -70,13 +76,13 @@ Hence when defining some new data structure, if we can define a `foldLeft` and Note that, in order to support laziness, the signature of `Foldable`'s `foldRight` is -``` +```scala def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] ``` as opposed to -``` +```scala def foldRight[A, B](fa: F[A], z: B)(f: (A, B) => B): B ``` diff --git a/docs/src/main/tut/functor.md b/docs/src/main/tut/functor.md index a25c589cc6..612bdbbd4d 100644 --- a/docs/src/main/tut/functor.md +++ b/docs/src/main/tut/functor.md @@ -34,11 +34,13 @@ Vector(1,2,3).map(_.toString) We can trivially create a `Functor` instance for a type which has a well behaved `map` method: -```tut +```tut:silent import cats._ + implicit val optionFunctor: Functor[Option] = new Functor[Option] { def map[A,B](fa: Option[A])(f: A => B) = fa map f } + implicit val listFunctor: Functor[List] = new Functor[List] { def map[A,B](fa: List[A])(f: A => B) = fa map f } @@ -48,7 +50,7 @@ However, functors can also be created for types which don't have a `map` method. For example, if we create a `Functor` for `Function1[In, ?]` we can use `andThen` to implement `map`: -```tut +```tut:silent implicit def function1Functor[In]: Functor[Function1[In, ?]] = new Functor[Function1[In, ?]] { def map[A,B](fa: In => A)(f: A => B): Function1[In,B] = fa andThen f @@ -79,10 +81,8 @@ Functor[List].map(List("qwer", "adsfg"))(len) is a `Some`: ```tut -// Some(x) case: function is applied to x; result is wrapped in Some -Functor[Option].map(Some("adsf"))(len) -// None case: simply returns None (function is not applied) -Functor[Option].map(None)(len) +Functor[Option].map(Some("adsf"))(len) // Some(x) case: function is applied to x; result is wrapped in Some +Functor[Option].map(None)(len) // None case: simply returns None (function is not applied) ``` ## Derived methods diff --git a/docs/src/main/tut/kleisli.md b/docs/src/main/tut/kleisli.md index f9119cb162..58b0943631 100644 --- a/docs/src/main/tut/kleisli.md +++ b/docs/src/main/tut/kleisli.md @@ -23,7 +23,7 @@ One of the most useful properties of functions is that they **compose**. That is this compositional property that we are able to write many small functions and compose them together to create a larger one that suits our needs. -```tut +```tut:silent val twice: Int => Int = x => x * 2 @@ -31,15 +31,18 @@ val countCats: Int => String = x => if (x == 1) "1 cat" else s"$x cats" val twiceAsManyCats: Int => String = - twice andThen countCats - // equivalent to: countCats compose twice + twice andThen countCats // equivalent to: countCats compose twice +``` +Thus. + +```tut twiceAsManyCats(1) // "2 cats" ``` Sometimes, our functions will need to return monadic values. For instance, consider the following set of functions. -```tut +```tut:silent val parse: String => Option[Int] = s => if (s.matches("-?[0-9]+")) Some(s.toInt) else None @@ -58,7 +61,7 @@ properties of the `F[_]`, we can do different things with `Kleisli`s. For instan `FlatMap[F]` instance (we can call `flatMap` on `F[A]` values), we can compose two `Kleisli`s much like we can two functions. -```tut +```tut:silent import cats.FlatMap import cats.syntax.flatMap._ @@ -70,7 +73,7 @@ final case class Kleisli[F[_], A, B](run: A => F[B]) { Returning to our earlier example: -```tut +```tut:silent // Bring in cats.FlatMap[Option] instance import cats.std.option._ @@ -87,7 +90,7 @@ It is important to note that the `F[_]` having a `FlatMap` (or a `Monad`) instan we can do useful things with weaker requirements. Such an example would be `Kleisli#map`, which only requires that `F[_]` have a `Functor` instance (e.g. is equipped with `map: F[A] => (A => B) => F[B]`). -```tut +```tut:silent import cats.Functor final case class Kleisli[F[_], A, B](run: A => F[B]) { @@ -117,7 +120,7 @@ resolution will pick up the most specific instance it can (depending on the `F[_ An example of a `Monad` instance for `Kleisli` would be: -```tut +```tut:silent import cats.syntax.flatMap._ import cats.syntax.functor._ // Alternatively we can import cats.implicits._ to bring in all the @@ -179,7 +182,7 @@ That is, we take a read-only value, and produce some value with it. For this rea functions often refer to the function as a `Reader`. For instance, it is common to hear about the `Reader` monad. In the same spirit, Cats defines a `Reader` type alias along the lines of: -```tut +```tut:silent // We want A => B, but Kleisli provides A => F[B]. To make the types/shapes match, // we need an F[_] such that providing it a type A is equivalent to A // This can be thought of as the type-level equivalent of the identity function @@ -210,7 +213,7 @@ Let's look at some example modules, where each module has it's own configuration If the configuration is good, we return a `Some` of the module, otherwise a `None`. This example uses `Option` for simplicity - if you want to provide error messages or other failure context, consider using `Xor` instead. -```tut +```tut:silent case class DbConfig(url: String, user: String, pass: String) trait Db object Db { @@ -229,7 +232,7 @@ data over the web). Both depend on their own configuration parameters. Neither k should be. However our application needs both of these modules to work. It is plausible we then have a more global application configuration. -```tut +```tut:silent case class AppConfig(dbConfig: DbConfig, serviceConfig: ServiceConfig) class App(db: Db, service: Service) @@ -239,7 +242,7 @@ As it stands, we cannot use both `Kleisli` validation functions together nicely other a `ServiceConfig`. That means the `FlatMap` (and by extension, the `Monad`) instances differ (recall the input type is fixed in the type class instances). However, there is a nice function on `Kleisli` called `local`. -```tut +```tut:silent final case class Kleisli[F[_], A, B](run: A => F[B]) { def local[AA](f: AA => A): Kleisli[F, AA, B] = Kleisli(f.andThen(run)) } @@ -251,7 +254,7 @@ so long as we tell it how to go from an `AppConfig` to the other configs. Now we can create our application config validator! -```tut +```tut:silent final case class Kleisli[F[_], Z, A](run: Z => F[A]) { def flatMap[B](f: A => Kleisli[F, Z, B])(implicit F: FlatMap[F]): Kleisli[F, Z, B] = Kleisli(z => F.flatMap(run(z))(a => f(a).run(z))) diff --git a/docs/src/main/tut/monad.md b/docs/src/main/tut/monad.md index a751480d9d..84664d0004 100644 --- a/docs/src/main/tut/monad.md +++ b/docs/src/main/tut/monad.md @@ -33,7 +33,7 @@ We can use `flatten` to define `flatMap`: `flatMap` is just `map` followed by `flatten`. Conversely, `flatten` is just `flatMap` using the identity function `x => x` (i.e. `flatMap(_)(x => x)`). -```tut +```tut:silent import cats._ implicit def optionMonad(implicit app: Applicative[Option]) = @@ -52,7 +52,7 @@ implicit def optionMonad(implicit app: Applicative[Option]) = follows this tradition by providing implementations of `flatten` and `map` derived from `flatMap` and `pure`. -```tut +```tut:silent implicit val listMonad = new Monad[List] { def flatMap[A, B](fa: List[A])(f: A => List[B]): List[B] = fa.flatMap(f) def pure[A](a: A): List[A] = List(a) @@ -94,7 +94,7 @@ instructions on how to compose any outer monad (`F` in the following example) with a specific inner monad (`Option` in the following example). -```tut +```tut:silent case class OptionT[F[_], A](value: F[Option[A]]) implicit def optionTMonad[F[_]](implicit F : Monad[F]) = { diff --git a/docs/src/main/tut/monoid.md b/docs/src/main/tut/monoid.md index 8ff8f37f7c..e9f9b6020f 100644 --- a/docs/src/main/tut/monoid.md +++ b/docs/src/main/tut/monoid.md @@ -12,7 +12,9 @@ source: "https://github.com/non/algebra/blob/master/core/src/main/scala/algebra/ value that when combined with any other instance of that type returns the other instance, i.e. - (combine(x, empty) == combine(empty, x) == x) +```scala +(combine(x, empty) == combine(empty, x) == x) +``` For example, if we have a `Monoid[String]` with `combine` defined as string concatenation, then `empty = ""`. @@ -21,11 +23,18 @@ Having an `empty` defined allows us to combine all the elements of some potentially empty collection of `T` for which a `Monoid[T]` is defined and return a `T`, rather than an `Option[T]` as we have a sensible default to fall back to. - -```tut + +First some imports. + +```tut:silent import cats._ import cats.std.all._ +import cats.implicits._ +``` +Examples. + +```tut Monoid[String].empty Monoid[String].combineAll(List("a", "b", "c")) Monoid[String].combineAll(List()) @@ -36,29 +45,26 @@ specific ones for each type, is that we can compose monoids to allow us to operate on more complex types, e.g. ```tut -import cats._ -import cats.std.all._ - Monoid[Map[String,Int]].combineAll(List(Map("a" -> 1, "b" -> 2), Map("a" -> 3))) Monoid[Map[String,Int]].combineAll(List()) ``` This is also true if we define our own instances. As an example, let's use [`Foldable`](foldable.html)'s `foldMap`, which maps over values accumulating -the results, using the available `Monoid` for the type mapped onto. To use this -with a function that produces a tuple, we can define a `Monoid` for a tuple -that will be valid for any tuple where the types it contains also have a -`Monoid` available: +the results, using the available `Monoid` for the type mapped onto. ```tut -import cats._ -import cats.implicits._ - val l = List(1, 2, 3, 4, 5) - l.foldMap(identity) l.foldMap(i => i.toString) +``` +To use this +with a function that produces a tuple, we can define a `Monoid` for a tuple +that will be valid for any tuple where the types it contains also have a +`Monoid` available: + +```tut:silent implicit def tupleMonoid[A : Monoid, B : Monoid]: Monoid[(A, B)] = new Monoid[(A, B)] { def combine(x: (A, B), y: (A, B)): (A, B) = { @@ -68,7 +74,11 @@ implicit def tupleMonoid[A : Monoid, B : Monoid]: Monoid[(A, B)] = } def empty: (A, B) = (Monoid[A].empty, Monoid[B].empty) } +``` + +Thus. +```tut l.foldMap(i => (i, i.toString)) // do both of the above in one pass, hurrah! ``` diff --git a/docs/src/main/tut/semigroup.md b/docs/src/main/tut/semigroup.md index a23ef66c79..1cd396efaf 100644 --- a/docs/src/main/tut/semigroup.md +++ b/docs/src/main/tut/semigroup.md @@ -12,21 +12,32 @@ A semigroup for some given type A has a single operation returns a value of type A. This operation must be guaranteed to be associative. That is to say that: - ((a combine b) combine c) +```scala +((a combine b) combine c) +``` must be the same as - - (a combine (b combine c)) + +```scala +(a combine (b combine c)) +``` for all possible values of a,b,c. There are instances of `Semigroup` defined for many types found in the scala common library: -```tut +First some imports. + +```tut:silent import cats._ import cats.std.all._ +import cats.implicits._ +``` +Examples. + +```tut Semigroup[Int].combine(1, 2) Semigroup[List[Int]].combine(List(1,2,3), List(4,5,6)) Semigroup[Option[Int]].combine(Option(1), Option(2)) @@ -40,10 +51,7 @@ value of having a `Semigroup` typeclass available is that these compose, so for instance, we can say ```tut -import cats.implicits._ - Map("foo" -> Map("bar" -> 5)).combine(Map("foo" -> Map("bar" -> 6), "baz" -> Map())) - Map("foo" -> List(1, 2)).combine(Map("foo" -> List(3,4), "bar" -> List(42))) ``` @@ -54,12 +62,11 @@ Map("foo" -> Map("bar" -> 5)) ++ Map("foo" -> Map("bar" -> 6), "baz" -> Map()) Map("foo" -> List(1, 2)) ++ Map("foo" -> List(3,4), "bar" -> List(42)) ``` - There is inline syntax available for `Semigroup`. Here we are -following the convention from scalaz, that`|+|` is the +following the convention from scalaz, that `|+|` is the operator from `Semigroup`. -```tut +```tut:silent import cats.syntax.all._ import cats.implicits._ import cats.std._ @@ -67,7 +74,11 @@ import cats.std._ val one = Option(1) val two = Option(2) val n: Option[Int] = None +``` +Thus. + +```tut one |+| two n |+| two n |+| n diff --git a/docs/src/main/tut/semigroupk.md b/docs/src/main/tut/semigroupk.md index d47a1b3bac..0f3e837883 100644 --- a/docs/src/main/tut/semigroupk.md +++ b/docs/src/main/tut/semigroupk.md @@ -13,11 +13,15 @@ Before introducing a `SemigroupK`, it makes sense to talk about what a returns a value of type `A`. This operation must be guaranteed to be associative. That is to say that: - ((a combine b) combine c) +```scala +((a combine b) combine c) +``` must be the same as - (a combine (b combine c)) +```scala +(a combine (b combine c)) +``` for all possible values of `a`, `b`, `c`. @@ -33,10 +37,14 @@ defines type aliases to the `Semigroup` from algebra, so that you can There are instances of `Semigroup` defined for many types found in the scala common library: -```tut +```tut:silent import cats._ import cats.std.all._ +``` + +Examples. +```tut Semigroup[Int].combine(1, 2) Semigroup[List[Int]].combine(List(1,2,3), List(4,5,6)) Semigroup[Option[Int]].combine(Option(1), Option(2)) @@ -89,7 +97,7 @@ There is inline syntax available for both `Semigroup` and `|+|` is the operator from semigroup and that `<+>` is the operator from `SemigroupK` (called `Plus` in scalaz). -```tut +```tut:silent import cats.syntax.all._ import cats.implicits._ import cats.std._ @@ -97,7 +105,11 @@ import cats.std._ val one = Option(1) val two = Option(2) val n: Option[Int] = None +``` +Thus. + +```tut one |+| two one <+> two n |+| two diff --git a/docs/src/main/tut/traverse.md b/docs/src/main/tut/traverse.md index f4de95ce4a..eb6b8e448d 100644 --- a/docs/src/main/tut/traverse.md +++ b/docs/src/main/tut/traverse.md @@ -14,17 +14,20 @@ These effects tend to show up in functions working on a single piece of data - f parsing a single `String` into an `Int`, validating a login, or asynchronously fetching website information for a user. -```tut +```tut:silent +import cats.data.Xor +import scala.concurrent.Future + def parseInt(s: String): Option[Int] = ??? -import cats.data.Xor trait SecurityError trait Credentials + def validateLogin(cred: Credentials): Xor[SecurityError, Unit] = ??? -import scala.concurrent.Future trait Profile trait User + def userInfo(user: User): Future[Profile] = ??? ``` @@ -86,7 +89,7 @@ to allow it to infer the `Applicative[Xor[A, ?]]` and `Applicative[Validated[A, instances - `scalac` has issues inferring the instances for data types that do not trivially satisfy the `F[_]` shape required by `Applicative`. -```tut +```tut:silent import cats.Semigroup import cats.data.{NonEmptyList, OneAnd, Validated, ValidatedNel, Xor} import cats.std.list._ @@ -97,16 +100,27 @@ def parseIntXor(s: String): Xor[NumberFormatException, Int] = def parseIntValidated(s: String): ValidatedNel[NumberFormatException, Int] = Validated.catchOnly[NumberFormatException](s.toInt).toValidatedNel +``` +Examples. + +```tut val x1 = List("1", "2", "3").traverseU(parseIntXor) val x2 = List("1", "abc", "3").traverseU(parseIntXor) val x3 = List("1", "abc", "def").traverseU(parseIntXor) +``` -// Need proof that NonEmptyList[A] is a Semigroup for there to be an -// Applicative instance for ValidatedNel +We need proof that `NonEmptyList[A]` is a `Semigroup `for there to be an `Applicative` instance for +`ValidatedNel`. + +```tut:silent implicit def nelSemigroup[A]: Semigroup[NonEmptyList[A]] = OneAnd.oneAndSemigroupK[List].algebra[A] +``` +Thus. + +```tut val v1 = List("1", "2", "3").traverseU(parseIntValidated) val v2 = List("1", "abc", "3").traverseU(parseIntValidated) val v3 = List("1", "abc", "def").traverseU(parseIntValidated) @@ -133,7 +147,7 @@ a type alias for `Kleisli[Id, E, A]` which is a wrapper around `E => A`. If we fix `E` to be some sort of environment or configuration, we can use the `Reader` applicative in our traverse. -```tut +```tut:silent import cats.data.Reader trait Context @@ -153,8 +167,9 @@ that topic. (Note that since a `Job` is just a `Reader`/`Kleisli`, one could wri Corresponding to our bunches of data are bunches of topics, a `List[Topic]` if you will. Since `Reader` has an `Applicative` instance, we can `traverse` over this list with `processTopic`. -```tut -def processTopics(topics: List[Topic]) = topics.traverse(processTopic) +```tut:silent +def processTopics(topics: List[Topic]) = + topics.traverse(processTopic) ``` Note the nice return type - `Job[List[Result]]`. We now have one aggregate `Job` that when run, @@ -186,9 +201,7 @@ Given `Option` has an `Applicative` instance, we can traverse over the list with ```tut import cats.std.option._ - val l1 = List(Option(1), Option(2), Option(3)).traverse(identity) - val l2 = List(Option(1), None, Option(3)).traverse(identity) ``` @@ -196,7 +209,6 @@ val l2 = List(Option(1), None, Option(3)).traverse(identity) ```tut val l1 = List(Option(1), Option(2), Option(3)).sequence - val l2 = List(Option(1), None, Option(3)).sequence ``` @@ -204,19 +216,19 @@ val l2 = List(Option(1), None, Option(3)).sequence Sometimes our effectful functions return a `Unit` value in cases where there is no interesting value to return (e.g. writing to some sort of store). -```tut +```tut:silent trait Data - def writeToStore(data: Data): Future[Unit] = ??? ``` If we traverse using this, we end up with a funny type. -```tut +```tut:silent import cats.std.future._ import scala.concurrent.ExecutionContext.Implicits.global -def writeManyToStore(data: List[Data]) = data.traverse(writeToStore) +def writeManyToStore(data: List[Data]) = + data.traverse(writeToStore) ``` We end up with a `Future[List[Unit]]`! A `List[Unit]` is not of any use to us, and communicates the @@ -226,13 +238,16 @@ Traversing solely for the sake of the effect (ignoring any values that may be pr is common, so `Foldable` (superclass of `Traverse`) provides `traverse_` and `sequence_` methods that do the same thing as `traverse` and `sequence` but ignores any value produced along the way, returning `Unit` at the end. -```tut +```tut:silent import cats.syntax.foldable._ -def writeManyToStore(data: List[Data]) = data.traverse_(writeToStore) +def writeManyToStore(data: List[Data]) = + data.traverse_(writeToStore) // Int values are ignored with traverse_ -def writeToStoreV2(data: Data): Future[Int] = ??? +def writeToStoreV2(data: Data): Future[Int] = + ??? -def writeManyToStoreV2(data: List[Data]) = data.traverse_(writeToStoreV2) +def writeManyToStoreV2(data: List[Data]) = + data.traverse_(writeToStoreV2) ``` diff --git a/docs/src/main/tut/typeclasses.md b/docs/src/main/tut/typeclasses.md index e698e8a325..5084b1c5b2 100644 --- a/docs/src/main/tut/typeclasses.md +++ b/docs/src/main/tut/typeclasses.md @@ -4,7 +4,7 @@ The type class pattern is a ubiquitous pattern in Scala, its function is to provide a behavior for some type. You think of it as an "interface" in the Java sense. Here's an example. -```tut +```tut:silent /** * A type class to provide textual representation */ @@ -17,7 +17,7 @@ into `String`s. Now we can write a function which is polymorphic on some `A`, as long as we have some value of `Show[A]`, so that our function can have a way of producing a `String`: -```tut +```tut:silent def log[A](a: A)(implicit s: Show[A]) = println(s.show(a)) ``` @@ -30,11 +30,15 @@ log("a string") It is trivial to supply a `Show` instance for `String`: -```tut +```tut:silent implicit val stringShow = new Show[String] { def show(s: String) = s } -// and now our call to Log succeeds +``` + +and now our call to Log succeeds + +```tut log("a string") ``` @@ -51,7 +55,7 @@ For some types, providing a `Show` instance might depend on having some implicit `Show` instance of some other type, for instance, we could implement `Show` for `Option`: -```tut +```tut:silent implicit def optionShow[A](implicit sa: Show[A]) = new Show[Option[A]] { def show(oa: Option[A]): String = oa match { case None => "None" @@ -69,13 +73,13 @@ log(Option(Option("hello"))) Scala has syntax just for this pattern that we use frequently: -```scala -def log[A : Show](a: A) = println(implicitly[Show[A]].show(a)) +```tut:silent +def log[A: Show](a: A) = println(implicitly[Show[A]].show(a)) ``` is the same as -```scala +```tut:silent def log[A](a: A)(implicit s: Show[A]) = println(s.show(a)) ``` diff --git a/docs/src/main/tut/validated.md b/docs/src/main/tut/validated.md index 2d61585151..81ba76075f 100644 --- a/docs/src/main/tut/validated.md +++ b/docs/src/main/tut/validated.md @@ -41,7 +41,7 @@ As our running example, we will look at config parsing. Our config will be repre `Map[String, String]`. Parsing will be handled by a `Read` type class - we provide instances just for `String` and `Int` for brevity. -```tut +```tut:silent trait Read[A] { def read(s: String): Option[A] } @@ -65,7 +65,7 @@ Then we enumerate our errors - when asking for a config value, one of two things go wrong: the field is missing, or it is not well-formed with regards to the expected type. -```tut +```tut:silent sealed abstract class ConfigError final case class MissingConfig(field: String) extends ConfigError final case class ParseError(field: String) extends ConfigError @@ -85,7 +85,7 @@ object Validated { Now we are ready to write our parser. -```tut +```tut:silent import cats.data.Validated import cats.data.Validated.{Invalid, Valid} @@ -106,7 +106,7 @@ Everything is in place to write the parallel validator. Recall that we can only validation if each piece is independent. How do we enforce the data is independent? By asking for all of it up front. Let's start with two pieces of data. -```tut +```tut:silent def parallelValidate[E, A, B, C](v1: Validated[E, A], v2: Validated[E, B])(f: (A, B) => C): Validated[E, C] = (v1, v2) match { case (Valid(a), Valid(b)) => Valid(f(a, b)) @@ -122,7 +122,7 @@ but that seems needlessly specific - clients may want to define their own way of How then do we abstract over a binary operation? The `Semigroup` type class captures this idea. -```tut +```tut:silent import cats.Semigroup def parallelValidate[E : Semigroup, A, B, C](v1: Validated[E, A], v2: Validated[E, B])(f: (A, B) => C): Validated[E, C] = @@ -144,7 +144,7 @@ Additionally, the type alias `ValidatedNel[E, A]` is provided. Time to parse. -```tut +```tut:silent import cats.SemigroupK import cats.data.NonEmptyList import cats.std.list._ @@ -158,7 +158,11 @@ implicit val nelSemigroup: Semigroup[NonEmptyList[ConfigError]] = implicit val readString: Read[String] = Read.stringRead implicit val readInt: Read[Int] = Read.intRead +``` + +Any and all errors are reported! +```tut val v1 = parallelValidate(config.parse[String]("url").toValidatedNel, config.parse[Int]("port").toValidatedNel)(ConnectionParams.apply) @@ -170,8 +174,6 @@ val v3 = parallelValidate(config.parse[String]("endpoint").toValidatedNel, config.parse[Int]("port").toValidatedNel)(ConnectionParams.apply) ``` -Any and all errors are reported! - ## Apply Our `parallelValidate` function looks awfully like the `Apply#map2` function. @@ -183,7 +185,7 @@ Which can be defined in terms of `Apply#ap` and `Apply#map`, the very functions Can we perhaps define an `Apply` instance for `Validated`? Better yet, can we define an `Applicative` instance? -```tut +```tut:silent import cats.Applicative implicit def validatedApplicative[E : Semigroup]: Applicative[Validated[E, ?]] = @@ -205,7 +207,7 @@ Awesome! And now we also get access to all the goodness of `Applicative`, among We can now easily ask for several bits of configuration and get any and all errors returned back. -```tut +```tut:silent import cats.Apply import cats.data.ValidatedNel @@ -216,7 +218,11 @@ val config = Config(Map(("name", "cat"), ("age", "not a number"), ("houseNumber" case class Address(houseNumber: Int, street: String) case class Person(name: String, age: Int, address: Address) +``` +Thus. + +```tut val personFromConfig: ValidatedNel[ConfigError, Person] = Apply[ValidatedNel[ConfigError, ?]].map4(config.parse[String]("name").toValidatedNel, config.parse[Int]("age").toValidatedNel, @@ -230,7 +236,7 @@ val personFromConfig: ValidatedNel[ConfigError, Person] = `Option` has `flatMap`, `Xor` has `flatMap`, where's `Validated`'s? Let's try to implement it - better yet, let's implement the `Monad` type class. -```tut +```tut:silent import cats.Monad implicit def validatedMonad[E]: Monad[Validated[E, ?]] = @@ -247,7 +253,7 @@ implicit def validatedMonad[E]: Monad[Validated[E, ?]] = Note that all `Monad` instances are also `Applicative` instances, where `ap` is defined as -```tut +```tut:silent trait Monad[F[_]] { def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] def pure[A](x: A): F[A] @@ -296,16 +302,21 @@ val houseNumber = config.parse[Int]("house_number").andThen{ n => ### `withXor` The `withXor` method allows you to temporarily turn a `Validated` instance into an `Xor` instance and apply it to a function. -```tut +```tut:silent import cats.data.Xor def positive(field: String, i: Int): ConfigError Xor Int = { if (i >= 0) Xor.right(i) else Xor.left(ParseError(field)) } +``` +Thus. + +```tut val houseNumber = config.parse[Int]("house_number").withXor{ xor: ConfigError Xor Int => xor.flatMap{ i => - positive(i) + positive("house_number", i) } +} ``` diff --git a/docs/src/main/tut/xor.md b/docs/src/main/tut/xor.md index 3c676706d9..80b2099b6a 100644 --- a/docs/src/main/tut/xor.md +++ b/docs/src/main/tut/xor.md @@ -100,7 +100,7 @@ over `M[_] : Monad`). Since we only ever want the computation to continue in the case of `Xor.Right` (as captured by the right-bias nature), we fix the left type parameter and leave the right one free. -```tut +```tut:silent import cats.Monad implicit def xorMonad[Err]: Monad[Xor[Err, ?]] = @@ -118,7 +118,7 @@ take the reciprocal, and then turn the reciprocal into a string. In exception-throwing code, we would have something like this: -```tut +```tut:silent object ExceptionStyle { def parse(s: String): Int = if (s.matches("-?[0-9]+")) s.toInt @@ -134,7 +134,7 @@ object ExceptionStyle { Instead, let's make the fact that some of our functions can fail explicit in the return type. -```tut +```tut:silent object XorStyle { def parse(s: String): Xor[NumberFormatException, Int] = if (s.matches("-?[0-9]+")) Xor.right(s.toInt) @@ -150,7 +150,7 @@ object XorStyle { Now, using combinators like `flatMap` and `map`, we can compose our functions together. -```tut +```tut:silent import XorStyle._ def magic(s: String): Xor[Exception, String] = @@ -181,7 +181,7 @@ This implies that there is still room to improve. Instead of using exceptions as our error value, let's instead enumerate explicitly the things that can go wrong in our program. -```tut +```tut:silent object XorStyle { sealed abstract class Error final case class NotANumber(string: String) extends Error @@ -221,7 +221,7 @@ magic("123") match { Once you start using `Xor` for all your error-handling, you may quickly run into an issue where you need to call into two separate modules which give back separate kinds of errors. -```tut +```tut:silent sealed abstract class DatabaseError trait DatabaseValue @@ -240,7 +240,7 @@ object Service { Let's say we have an application that wants to do database things, and then take database values and do service things. Glancing at the types, it looks like `flatMap` will do it. -```tut +```tut:silent def doApp = Database.databaseThings().flatMap(Service.serviceThings) ``` @@ -257,7 +257,7 @@ to unify the `E1` and `E2` in a `flatMap` call - in our case, the closest common So clearly in order for us to easily compose `Xor` values, the left type parameter must be the same. We may then be tempted to make our entire application share an error data type. -```tut +```tut:silent sealed abstract class AppError final case object DatabaseError1 extends AppError final case object DatabaseError2 extends AppError @@ -286,7 +286,7 @@ must inspect **all** the `AppError` cases, even though it was only intended for Instead of lumping all our errors into one big ADT, we can instead keep them local to each module, and have an application-wide error ADT that wraps each error ADT we need. -```tut +```tut:silent sealed abstract class DatabaseError trait DatabaseValue @@ -312,7 +312,7 @@ Now in our outer application, we can wrap/lift each module-specific error into ` call our combinators as usual. `Xor` provides a convenient method to assist with this, called `Xor.leftMap` - it can be thought of as the same as `map`, but for the `Left` side. -```tut +```tut:silent def doApp: Xor[AppError, ServiceValue] = Database.databaseThings().leftMap(AppError.Database). flatMap(dv => Service.serviceThings(dv).leftMap(AppError.Service)) @@ -322,7 +322,7 @@ Hurrah! Each module only cares about its own errors as it should be, and more co own error ADT that encapsulates each constituent module's error ADT. Doing this also allows us to take action on entire classes of errors instead of having to pattern match on each individual one. -```tut +```tut:silent def awesome = doApp match { case Xor.Left(AppError.Database(_)) => "something in the database went wrong"