A relaxed chat room about all things Scala. Beginner questions welcome. http://scala-lang.org/conduct/ applies
lrytz on 2.13.x
Regression test per eed3si9n Merge pull request #9454 from s… (compare)
lrytz on 2.12.x
Fix race condition in PipelineM… Merge pull request #9455 from r… (compare)
retronym on 2.12.x
Fix and extend Array.apply vara… Merge pull request #9356 from r… (compare)
@tirumalesh123 lift
is just another name for map
, with a slightly rearranged signature.map
normally looks like def map(fa: F[A])(f: A => B): F[B]
. If you rearrange the arguments you get def lift(f: A => B): F[A] => F[B]
, so you can look at Functor
as the api for lifting functions of one argument in F
. This extends to Applicative, which lets you lift functions of multiple arguments into F
, and ultimately into Monad
, which gives you the ability to change the structure of one computation based on the result of another.
et's say I have a method which returns optional if I want to get the value inside optional should I use lifting functions
yeah, pretty much. You should just map
(or flatMap
) and transform the Option
that way. I don't particularly like saying "the value inside the F
" because it's misleading in the long run, but it's a decent approximation at first
Deserializer[A](run: Array[Byte] => A)
A => B
giving us a Deserializer[B]
Serializer[A]
but basically it starts from thinking about what types are for (and not what they are against, to quote Connor McBride), to the fact that they are given meaning and semantics not by their underlying representation, but by the operations you define on them (let's say just functions for now).
The second step would be defining algebras as specifications of part of the behaviour of a data type. This works really well with typeclasses, which give you an has a
, rather than the is a relationship you typically get from OO style interfaces. The result of this thought process is that given a datatype, part of what it can do is specified by operations that are unique to that type, and part by algebras (i.e. Monoid, Functor, and so on). This kind of reasoning can be explained with simple types and lower kinded typeclasses only.
Then, you move on to explaining how types of higher kind can be used not just for containers, but for computations as well: List and Option are interesting because they can be viewed both ways, but there are somethings that really only make sense as computations (like State or IO).
At this point you can actually explain F-A-M as algebras that specify part of the behaviour of higher kinded types:
The final bit is learning how to operate on types based on their algebras and operations only, while being agnostic to their representation (e.g avoiding pattern matching on Option
): this is propedeutic to learning about types which either have an opaque representation (IO
) or a very complex one (fs2.Stream
). It also means that you can tackle a new library which exposes different types, and basically know most of what you need to do to use it once you know which algebras it forms (e.g. doobie ConnectionIO).
I guess the main problem with this approach is that it requires some upfront motivation, and ideally a mentor to give you clear explanations and "unstuck" you along the way
@dsebban_twitter
IO
)
Vector
branching factor, you might try the scala/contributors room, and/or https://contributors.scala-lang.org
Vector("a","b","c","d")
, since in 2.13 these will be passed as an ArraySeq[String]
, we could just share the underlying array with the arrayseq like...object Vector {
def apply[A](elems: A*): Vector[A] =
if (elems.length <= 32 && elems.unsafeArray.isInstanceOf[Array[AnyRef]]) {
new Vector(0, elems.unsafeArray, 0)
} else { ... }
}