- ๐ 2019-04-19
- this spans many weeks / investment times
- ๐น Screencast: Functional Structures
- ๐จโ๐ป๐๏ธ an experienced OOP programmer learning FP and Scala
- and maybe category theory? ๐ค
- Cool REPL command:
:k TYPEwhich reveals theKindofTYPE๐- e.g.,
:k Int=>A:k List=>F[+A]
- e.g.,
-
A Higher Kinded Type
- can not be the value of an expression.
- A
List(alone) can not be the value of an expression. But, aList[Thinger]can be.Listis the Higher Kinded TypeThingeris the Proper Type
- A Higher Kinded Type can be thought of as a function that takes a
Proper Type and returns a new Proper Type
- i.e., the
F[A], orList[Thinger] - This is also called a Type Constructor
- i.e., the
-
When defining a function/method where one argument is the result of applying a Proper Type to a Type Constructor, the TC must also be expressed as a type parameter
- For type parameters:
[F[_], A], theF[_]is a Type Constructor- specifically, a Type Constructor with one argument
- the arg could be
List(1)orSome(1)orRight(1)- but it can not be an
Int/A
- but it can not be an
- contrived example:
def bar[F[_], A](x: F[A], y: F[A]) = null- can be called as:
bar(Some(1), Some(2)) - or:
bar(List(1,2,3), List(1)- ๐ค ๐ : if this is true, then whatabout
F[_]"having only one argument?"
- ๐ค ๐ : if this is true, then whatabout
- it can not be called as:
bar(Some(1), List(2))as that uses two different Proper Types (OptionandList), and we only define one type parameter (A)
- For type parameters:
- Functor - a type class that abstracts over Type Constructors that can
define a Map operation
- ๐ 7:30
- code is more clear there ;)
- Simply put, its abstraction to define a pattern for how to map from one Higher Kinded Type to another
- expressed as:
trait Functor[F[_]] {}- will have a method like:
def map[A, B](fa: F[A])(f: A => B): F[B] - basically, defining
mapis half of the definintion of a Functor - the other half is the set of rules
mapmust comply with
- will have a method like:
- ๐ 7:30
- Functor Laws ๐ฉโโ๏ธ๐ฎ
- the set of rules that define how the
Functormaps - e.g., an identity law that states that for every function
fa: F[A], the result of.map(fa)(a => a)must=== fa- i.e.,
def identity[F[_], A](fa: F[A]) = Functor[F].map(fa)(a => a) === fa- ๐๏ธ
===is not real ๐ง
- ๐๏ธ
- ๐ 10:32
- above code is actually a
traitoutside of the contrivedFunctor - and since the above code lacks the actual ability to perform said
mapping, an
implicitcan be added to do the work: def identity[...](fa...)(implicit F: Functor[F]) = F.map(fa)(a => a) == fa
- above code is actually a
- i.e.,
- e.g., composition law states that for
FandG, we can compose them together as a single function, or, they can be composed piecewise through many functions
- the set of rules that define how the
def composition[F[_], A, B, C](fa: F[A], f: A => B, g: B => C)(implicit F: Functor[F]) =
F.map(F.map(fa)(f))(g) == F.map(fa)(f andThen g)-
๐๏ธ 14:05 for examples on Functor instances, via a companion object
Functor[List]is a valid functor, as our trait was:Functor[F[_]]- this implementation is simple, since
Listalready has amap()method - as do most std lib collections (
Option, etc)
- this implementation is simple, since
Functor[X => ?]-> afunction1Functor- ๐๏ธ it does not make sense to define a Functor for a Proper Type ๐๏ธ
- ๐๏ธ not to be confused with Funktion-One ๐ถ๏ธ
- ๐ทโโ๏ธ๏ธ
[X => ?]is a Type Constructor such that when a Proper Type,X, is applied to it, you get back a functionX => AorX => Betc. - ๐๏ธ
valcan not have a type param, only methods (def)- and fyi, a type parameter is required to define the
Xin[X => ?]
- and fyi, a type parameter is required to define the
function1Functor.map()can begin implementation as:def map[A, B](fa: X => A)(f: A => B): X => B =...
oh ๐ฉ๏ธ,Bhas nomap๐ค๏ธ โ- we need to return a new function
X => B-> the answer is compositionandThen๐๏ธ
def map[A, B](fa: X => A)(f: A => B): X => B = fa andThen f
-
lawfulness is determined by testing the given laws, e.g.,
identityor
composition.- testing any arbitrary values for the above examples would prove lawfulness
- ๐ค๏ธ so how does one define a chaotic functor? inquiring minds want to know!
- ๐ ๏ธ author describes this at ๐๏ธ 23:55
def lift[A, B](f: A => B): F[A] => F[B]- it is no longer pure as values are wrapped into that context
- implemented as:
def lift[A, B](f: A => B): F[A] => F[B] = fa => map(fa)(f)- ๐ค๏ธ so where did
facome from?
- ๐ค๏ธ so where did
def as[A, B](fa: F[A], b: => B): F[B] = map(fa)(_ => b)def void[A](fa: F[A]): F[Unit] = as(fa, ())
-
Break for refreshment @ 27:52
- ๐ 2019-07-12
- its been maybe 4-5 weeks since I watched this! ๐ ๏ธ
-
simulacrum - typeclass library
-
provides
@typeclassannotation -
@typeclassis an annotation that provides enrichments or extension methods for anF[A]- ๐ง magic with super ("scary") complicated types happen ~33:32
- ๐๏ธ note that searching for
Lambdain Scala will probably be painful and not provide any actual information, but also provide tons of information not-aboutLambdabut perhaps "lambdas" as a concept! Welcome to relying on web searches to learn about Scala!
- ๐๏ธ note that searching for
- more mysterious things happen with
.compose- apparently its very powerful! it can do more than the standard library!
- im not at all clear on what that is, but yah, sure!
- programmers frickin' love things that are "powerful" ๐ช๏ธ
- im not at all clear on what that is, but yah, sure!
- apparently its very powerful! it can do more than the standard library!
- actually, there is a grok'able example @ 37:00
- Im a believer, but this is still just a matter of faith!
- apparently, nothing in this section is going "very deep with Functor"
- but apparently it offers lots of things not in the standard Collections
library!
- which is what all language libraries do, so Im still not sold, at all, on why any of this is important
- software libraries: they add more power (cool story!)
- and I guess adding near-infinite increasing complexity somehow lets one get even more power? where is it? what is it? ๐ค๏ธ
- but apparently it offers lots of things not in the standard Collections
library!
- author seemed like he was just right about to explain
Lambdaand then does the typical Scala cultural thing where he talks a lot "about" it and "around" it but doesnt at all explain what it is.- are Scalaists really just Daoists? โฏ๏ธ
- the type that can be spoken is not the type!
- holy ๐ฉ๏ธ my brain hurts! ๐ง ๏ธ๐ข๏ธ
- are Scalaists really just Daoists? โฏ๏ธ
- ๐ง magic with super ("scary") complicated types happen ~33:32
- a thing that looks like:
Functor[({type l[a] = Function1[Int, a] })#l]- the
{}imply Structural Type. - the
#lis a Type Projection, which represents the type memberlof the structural type (defined in the{}) - this is a Type Lambda
- the
-
convience for anonymous Structural Types
- see cats kind projector
- this is where
Lambdacomes from!- ok, srsly, how useful is any of this if this much complexity is required?
- again, WHY is any of this important at all?
- why not juse use a tool (language) thats much simpler to explain?
- ok, srsly, how useful is any of this if this much complexity is required?
- this is where
- adds support for
F[X => ?]syntax
- see cats kind projector
-
The
Lambdakeyword defines type functions -
๐๐๐!
- ๐