From 390aa07be1f7d78a42dfc6eb4164f6ecacd047f0 Mon Sep 17 00:00:00 2001
From: danicheg API Documentation: ChainChain
Chain
is an immutable sequence data structure that allows constant time prepending, appending and concatenation.
This makes it especially efficient when used as a Monoid, e.g. with Validated or Writer.
- As such it aims to be used where List and Vector incur a performance penalty.
+ As such it aims to be used where List and Vector incur a performance penalty.
Cats also includes type class implementations to support using Chain
as a general-purpose collection type, including Traverse, Monad, and Alternative.Motivation
@@ -238,7 +238,7 @@ NonEmptyList semigroup), which by the nature of
List
is very inefficient.
If you use traverse with a data structure with n
elements and Writer or Validated as the Applicative type, you will end up with a runtime of O(n^2)
.
This is because, with List
, appending a single element requires iterating over the entire data structure and therefore takes linear time.
So List isn't all that great for this use case, so let's use Vector or NonEmptyVector` instead, right?
+So List isn't all that great for this use case, so let's use Vector or NonEmptyVector` instead, right?
Well, Vector
has its own problems and in this case it's unfortunately not that much faster than List
at all. You can check this blog post by Li Haoyi for some deeper insight into Vector
's issues.
Chain
evolved from what used to be fs2.Catenable
and Erik Osheim's Chain library.
Similar to List
, it is also a very simple data structure, but unlike List
it supports constant O(1) time append
, prepend
and concat
.
@@ -265,7 +265,7 @@
You can also create an Option of NonEmptyChain
from a Chain
or any other collection type:
You can also create an Option of NonEmptyChain
from a Chain
or any other collection type:
import cats.data._
NonEmptyChain.fromChain(Chain(1, 2, 3))
@@ -294,7 +294,7 @@ How it works
Chain
is implemented as a simple unbalanced binary tree ADT with four cases:
- an empty Chain
with no elements, a singleton Chain
with exactly one element, a concatenation of two chains, or a wrapper for a Seq.
+ an empty Chain
with no elements, a singleton Chain
with exactly one element, a concatenation of two chains, or a wrapper for a Seq.
In code it looks like this:
sealed abstract class Chain[+A]
diff --git a/datatypes/contt.html b/datatypes/contt.html
index 81a22c400c..d01aa94f56 100644
--- a/datatypes/contt.html
+++ b/datatypes/contt.html
@@ -286,7 +286,7 @@ ContT
Succeeded(user.id)
}
}
-// eval: Eval[UserUpdateResult] = cats.Later@7cb3b8c6
+// eval: Eval[UserUpdateResult] = cats.Later@37f9fc82
Finally we can run the resulting Eval
to actually execute the computation:
eval.value
// Persisting updated user to the DB: User(100,Bob,150)
@@ -308,7 +308,7 @@ // anotherComputation: ContT[Eval, UserUpdateResult, Map[String, String]] = FromFn(
// runAndThen = Single(
-// f = cats.data.ContT$$Lambda$11729/0x00007fea8bfe5a60@5c1c43e3,
+// f = cats.data.ContT$$Lambda$11795/0x00007f12bbff4168@7de4c77e,
// index = 0
// )
// )
@@ -319,7 +319,7 @@ Succeeded
(userFields("id").toInt)
}
}
-// anotherEval: Eval[UserUpdateResult] = cats.Eval$$anon$5@447e5453
+// anotherEval: Eval[UserUpdateResult] = cats.Eval$$anon$5@1ab22e3a
anotherEval.value
// Persisting these fields to the DB: Map(id -> 100, name -> Bob, age -> 150)
@@ -336,7 +336,7 @@ // updateUserModel: ContT[Eval, UserUpdateResult, User] = FromFn(
// runAndThen = Single(
-// f = cats.data.ContT$$Lambda$11729/0x00007fea8bfe5a60@33d5c760,
+// f = cats.data.ContT$$Lambda$11795/0x00007f12bbff4168@141cb51c,
// index = 0
// )
// )
@@ -370,7 +370,7 @@ updateUserModel
flatMap persistToDb flatMap publishEvent
// chainOfContinuations: ContT[Eval, UserUpdateResult, UserUpdateResult] = FromFn(
// runAndThen = Single(
-// f = cats.data.ContT$$Lambda$11733/0x00007fea8bfe63e8@2c435e49,
+// f = cats.data.ContT$$Lambda$11799/0x00007f12bbff4af0@3c9a479e,
// index = 0
// )
// )
@@ -381,7 +381,7 @@ finalResult
}
}
-// eval: Eval[UserUpdateResult] = cats.Eval$$anon$5@3a9f357e
+// eval: Eval[UserUpdateResult] = cats.Eval$$anon$5@14c7a16a
eval.value
// Updated user model
diff --git a/datatypes/eval.html b/datatypes/eval.html
index f4e82b143e..9444c2f86f 100644
--- a/datatypes/eval.html
+++ b/datatypes/eval.html
@@ -257,7 +257,7 @@ println
("Running expensive calculation...")
1 + 2 * 3
}
-// lazyEval: Eval[Int] = cats.Later@504049c6
+// lazyEval: Eval[Int] = cats.Later@45f10304
lazyEval.value
// Running expensive calculation...
@@ -276,7 +276,7 @@ println
("Running expensive calculation...")
1 + 2 * 3
}
-// always: Eval[Int] = cats.Always@241dfd26
+// always: Eval[Int] = cats.Always@313991b9
always.value
// Running expensive calculation...
diff --git a/datatypes/freeapplicative.html b/datatypes/freeapplicative.html
index 5be77e9223..52b8a3e2f7 100644
--- a/datatypes/freeapplicative.html
+++ b/datatypes/freeapplicative.html
@@ -275,7 +275,7 @@
val validator = prog.foldMap[FromString](compiler)
-// validator: FromString[Boolean] = cats.instances.Function1Instances$$anon$7$$Lambda$11891/0x00007fea8bd4f958@474dc89
+// validator: FromString[Boolean] = cats.instances.Function1Instances$$anon$7$$Lambda$11957/0x00007f12bb7b3648@182071b
validator("1234")
// res0: Boolean = false
validator("12345")
diff --git a/datatypes/freemonad.html b/datatypes/freemonad.html
index ff77091295..41292513d5 100644
--- a/datatypes/freemonad.html
+++ b/datatypes/freemonad.html
@@ -718,7 +718,7 @@ import TeletypeOps._
val state = program.foldMap(interpreter)
-// state: TeletypeState[Unit] = cats.data.IndexedStateT@17bc7a6
+// state: TeletypeState[Unit] = cats.data.IndexedStateT@373c878c
val initialState = Nil
// initialState: Nil.type = List()
val (stored, _) = state.run(initialState).value
@@ -789,7 +789,7 @@ val evaluated = hoisted.foldMap(tryInterpreter)
// evaluated: OptTry[Int] = OptionT(value = Success(value = Some(value = 12)))
diff --git a/datatypes/state.html b/datatypes/state.html
index f50ab2e9f3..a61853cc54 100644
--- a/datatypes/state.html
+++ b/datatypes/state.html
@@ -474,7 +474,7 @@ _
<- close
_ <- open
} yield ()
-// valid: IndexedStateT[Eval, Closed.type, Open.type, Unit] = cats.data.IndexedStateT@33ebe944
+// valid: IndexedStateT[Eval, Closed.type, Open.type, Unit] = cats.data.IndexedStateT@717b6e6
Note that the inferred type of valid
correctly models that this computation can be executed only with an initial Closed
state.
valid.run(Open)
// error: type mismatch;
@@ -483,7 +483,7 @@ valid.run(Closed)
-// res6: Eval[(Open.type, Unit)] = cats.Eval$$anon$1@4fed8034
+// res6: Eval[(Open.type, Unit)] = cats.Eval$$anon$1@25b7b00a
Bifunctor
also defines a convenience function called leftMap
, which is defined as follows:
def leftMap[A, B, C](fab: F[A, B])(f: A => C): F[C, B] = bimap(fab)(f, identity)
There is no rightMap
however - use map
instead. The reasoning behind this is that in Cats, the instances of
diff --git a/typeclasses/bimonad.html b/typeclasses/bimonad.html
index 925349979b..ef5a7eddab 100644
--- a/typeclasses/bimonad.html
+++ b/typeclasses/bimonad.html
@@ -263,7 +263,7 @@
Note the equivalence:
nelBimonad.pure(true).extract === NonEmptyList.one(true).head
// res0: Boolean = true
diff --git a/typeclasses/contravariant.html b/typeclasses/contravariant.html
index d4ed09c16e..768f0d4267 100644
--- a/typeclasses/contravariant.html
+++ b/typeclasses/contravariant.html
@@ -246,7 +246,7 @@ implicit val showSalary: Show[Salary] = showMoney.contramap(_.size)
-// showSalary: Show[Salary] = cats.Show$$anon$2$$Lambda$12681/0x00007fea8c29f438@6a887c18
+// showSalary: Show[Salary] = cats.Show$$anon$2$$Lambda$12747/0x00007f12bc2d4478@1b05484f
Salary(Money(1000)).show
// res0: String = "$1000"
@@ -266,7 +266,7 @@ class A
class B extends A
val b: B = new B
-// b: B = repl.MdocSession$MdocApp$B@4728e975
+// b: B = repl.MdocSession$MdocApp$B@7556071
val a: A = b
-// a: A = repl.MdocSession$MdocApp$B@4728e975
+// a: A = repl.MdocSession$MdocApp$B@7556071
val showA: Show[A] = Show.show(a => "a!")
-// showA: Show[A] = cats.Show$$$Lambda$12680/0x00007fea8c29efc0@16ad3e38
+// showA: Show[A] = cats.Show$$$Lambda$12746/0x00007f12bc2d4000@443b308d
val showB1: Show[B] = showA.contramap(b => b: A)
-// showB1: Show[B] = cats.Show$$anon$2$$Lambda$12681/0x00007fea8c29f438@70d097ed
+// showB1: Show[B] = cats.Show$$anon$2$$Lambda$12747/0x00007f12bc2d4478@6cdd14c9
val showB2: Show[B] = showA.contramap(identity[A])
-// showB2: Show[B] = cats.Show$$anon$2$$Lambda$12681/0x00007fea8c29f438@1acb64e7
+// showB2: Show[B] = cats.Show$$anon$2$$Lambda$12747/0x00007f12bc2d4478@3fd16a06
val showB3: Show[B] = Contravariant[Show].narrow[A, B](showA)
-// showB3: Show[B] = cats.Show$$$Lambda$12680/0x00007fea8c29efc0@16ad3e38
+// showB3: Show[B] = cats.Show$$$Lambda$12746/0x00007f12bc2d4000@443b308d
Subtyping relationships are "lifted backwards" by contravariant functors, such that if F
is a
lawful contravariant functor and B <: A
then F[A] <: F[B]
, which is expressed by Contravariant.narrow
.
import cats.Semigroup
import cats.syntax.all._
Semigroup[Int]
-// res8: Semigroup[Int] = cats.kernel.instances.IntGroup@66e834c2
+// res8: Semigroup[Int] = cats.kernel.instances.IntGroup@61a01722
Semigroup[String]
-// res9: Semigroup[String] = cats.kernel.instances.StringMonoid@4f5d61ad
+Instances for type constructors regardless of their type parameter such as List
(++
)
and Set
(union
)...
Semigroup[List[Byte]]
-// res10: Semigroup[List[Byte]] = cats.kernel.instances.ListMonoid@375a1e12
+// res10: Semigroup[List[Byte]] = cats.kernel.instances.ListMonoid@30957d46
Semigroup[Set[Int]]
-// res11: Semigroup[Set[Int]] = cats.kernel.instances.SetSemilattice@57c45c59
+// res11: Semigroup[Set[Int]] = cats.kernel.instances.SetSemilattice@22c87c0d
trait Foo
Semigroup[List[Foo]]
-// res12: Semigroup[List[Foo]] = cats.kernel.instances.ListMonoid@375a1e12
+// res12: Semigroup[List[Foo]] = cats.kernel.instances.ListMonoid@30957d46
And instances for type constructors that depend on (one of) their type parameters having instances such
as tuples (pointwise combine
).
Semigroup[(List[Foo], Int)]
-// res13: Semigroup[(List[Foo], Int)] = cats.kernel.Monoid$$anon$2@70ad2c47
+// res13: Semigroup[(List[Foo], Int)] = cats.kernel.Monoid$$anon$2@43306671
Consider a function that merges two Map
s that combines values if they share
diff --git a/typeclasses/show.html b/typeclasses/show.html
index 248277a9e1..22aa46e3a2 100644
--- a/typeclasses/show.html
+++ b/typeclasses/show.html
@@ -229,7 +229,7 @@
toString
on non case classes is mostly gibberish.
Consider the following example:
(new {}).toString
-// res0: String = "repl.MdocSession$MdocApp$$anon$1@7b60a068"
+// res0: String = "repl.MdocSession$MdocApp$$anon$1@7805408b"
The fact that this code compiles is a design flaw of the Java API.
We want to make things like this impossible, by offering the toString
equivalent as a type class, instead of the root of the class hierarchy.
In short, Show
allows us to only have String-conversions defined for the data types we actually want.
This still may not seem useful to you, because case classes already automatically implement toString
, while show
would have to be implemented manually for each case class.
Thankfully with the help of a small library called kittens a lot of type class instances including Show
can be derived automatically!
Cats also offers Show
syntax to make working with it easier.