Last active
August 29, 2015 14:01
-
-
Save webskin/ccdabdd901a4a673790c to your computer and use it in GitHub Desktop.
Scalaz Experiments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package sz | |
| import scalaz._ | |
| import scala.Some | |
| /** | |
| * Created by Mickaël Gauvin on 2/20/14. | |
| */ | |
| object ScalazExperiments { | |
| def testShow() { | |
| /* | |
| scalaz/syntax/package.scala : | |
| --------------------------- | |
| package scalaz | |
| package syntax | |
| trait Syntaxes { | |
| … | |
| object show extends ToShowOps | |
| … | |
| } | |
| scalaz/syntax/Ops.scala : | |
| ------------------------------ | |
| package scalaz.syntax | |
| trait Ops[A] { | |
| def self: A | |
| } | |
| scalaz/syntax/ShowSyntax.scala : | |
| ------------------------------ | |
| package scalaz | |
| package syntax | |
| /** Wraps a value `self` and provides methods related to `Show` */ | |
| trait ShowOps[F] extends Ops[F] { | |
| implicit def F: Show[F] | |
| //// | |
| final def show: Cord = F.show(self) | |
| final def shows: String = F.shows(self) | |
| final def print: Unit = Console.print(shows) | |
| final def println: Unit = Console.println(shows) | |
| //// | |
| } | |
| trait ToShowOps { | |
| // ------------------------------------------------------------ | |
| // ce qui est importé | |
| // ------------------------------------------------------------ | |
| implicit def ToShowOps[F](v: F)(implicit F0: Show[F]) = | |
| new ShowOps[F] { def self = v; implicit def F: Show[F] = F0 } | |
| // ------------------------------------------------------------ | |
| //// | |
| //// | |
| } | |
| trait ShowSyntax[F] { | |
| implicit def ToShowOps(v: F): ShowOps[F] = new ShowOps[F] { def self = v; implicit def F: Show[F] = ShowSyntax.this.F } | |
| def F: Show[F] | |
| //// | |
| //// | |
| } | |
| scalaz/Show.scala : | |
| ------------------------------ | |
| package scalaz | |
| //// | |
| /** | |
| * A typeclass for conversion to textual representation, done via | |
| * [[scalaz.Cord]] for efficiency. | |
| */ | |
| //// | |
| trait Show[F] { self => | |
| //// | |
| def show(f: F): Cord = Cord(shows(f)) | |
| def shows(f: F): String = show(f).toString | |
| def xmlText(f: F): scala.xml.Text = scala.xml.Text(shows(f)) | |
| // derived functions | |
| //// | |
| val showSyntax = new scalaz.syntax.ShowSyntax[F] { def F = Show.this } | |
| } | |
| object Show { | |
| @inline def apply[F](implicit F: Show[F]): Show[F] = F | |
| //// | |
| def showFromToString[A]: Show[A] = new Show[A] { | |
| override def shows(f: A): String = f.toString | |
| } | |
| /** For compatibility with Scalaz 6 */ | |
| def showA[A]: Show[A] = showFromToString[A] | |
| def show[A](f: A => Cord): Show[A] = new Show[A] { | |
| override def show(a: A): Cord = f(a) | |
| } | |
| def shows[A](f: A => String): Show[A] = new Show[A] { | |
| override def shows(a: A): String = f(a) | |
| } | |
| implicit def showContravariant: Contravariant[Show] = new Contravariant[Show] { | |
| def contramap[A, B](r: Show[A])(f: B => A): Show[B] = new Show[B] { | |
| override def show(b: B): Cord = r.show(f(b)) | |
| } | |
| } | |
| //// | |
| } | |
| */ | |
| /* | |
| // ------------------------------------------------------------ | |
| // ce qui est importé | |
| // ------------------------------------------------------------ | |
| implicit def ToShowOps[F](v: F)(implicit F0: Show[F]) = | |
| new ShowOps[F] { def self = v; implicit def F: Show[F] = F0 } | |
| import std.anyVal._ // default shows | |
| */ | |
| import syntax.show._ | |
| { | |
| /* | |
| IntShow correspond à F0 dans ToShowOps ce qui revient à avoir dans le scope : | |
| implicit def ToShowOps[Int](v: Int) = | |
| new ShowOps[Int] { def self = v; implicit def F: Show[Int] = IntShow } | |
| */ | |
| implicit val IntShow = new Show[Int] { | |
| override def shows(a: Int) = a.toString + " toto " | |
| } | |
| /* | |
| Du coup on a dans le scope une fonction capable de convertir un Int en ShowOps[Int]: | |
| implicit def ToShowOps[Int](v: Int): ShowOps[Int] | |
| proxifiant Show[Int] et proposant les methods : show, shows, print, println | |
| // Wraps a value `self` and provides methods related to `Show` | |
| trait ShowOps[F] extends Ops[F] { | |
| implicit def F: Show[F] | |
| //// | |
| final def show: Cord = F.show(self) | |
| final def shows: String = F.shows(self) | |
| final def print: Unit = Console.print(shows) | |
| final def println: Unit = Console.println(shows) | |
| //// | |
| } | |
| */ | |
| println(3.shows) // affiche 3 toto | |
| } | |
| { | |
| implicit val IntShow = new Show[Int] { | |
| override def shows(a: Int) = a.toString + " tata " | |
| } | |
| println(4.shows) // affiche 4 tata | |
| } | |
| { | |
| import std.anyVal._ | |
| println(4.shows) // affiche 4 | |
| } | |
| } | |
| /* | |
| From Haskell : | |
| The Functor class (haddock) is the most basic and ubiquitous type class in the Haskell libraries. | |
| A simple intuition is that a Functor represents a “container” of some sort, along with the ability to apply a | |
| function uniformly to every element in the container. For example, a list is a container of elements, | |
| and we can apply a function to every element of a list, using map. As another example, a binary tree is also a | |
| container of elements, and it’s not hard to come up with a way to recursively apply a function to every element in a tree. | |
| Another intuition is that a Functor represents some sort of “computational context”. | |
| This intuition is generally more useful, but is more difficult to explain, precisely because it is so general. | |
| Some examples later should help to clarify the Functor-as-context point of view. | |
| In the end, however, a Functor is simply what it is defined to be; | |
| doubtless there are many examples of Functor instances that don’t exactly | |
| fit either of the above intuitions. The wise student will focus their attention on definitions and examples, | |
| without leaning too heavily on any particular metaphor. Intuition will come, in time, on its own. | |
| Lois : | |
| trait FunctorLaw { | |
| /** The identity function, lifted, is a no-op. */ | |
| def identity[A](fa: F[A])(implicit FA: Equal[F[A]]): Boolean = FA.equal(map(fa)(x => x), fa) | |
| /** | |
| * A series of maps may be freely rewritten as a single map on a | |
| * composed function. | |
| */ | |
| def composite[A, B, C](fa: F[A], f1: A => B, f2: B => C)(implicit FC: Equal[F[C]]): Boolean = FC.equal(map(map(fa)(f1))(f2), map(fa)(f2 compose f1)) | |
| } | |
| The first law says that mapping the identity function over every item in a container has no effect. | |
| The second says that mapping a composition of two functions over every item in a container is the same as first | |
| mapping one function, and then mapping the other. | |
| scala> kind[Int] | |
| res0: String = Int's kind is *. | |
| This is a proper type. Int | |
| scala> kind[Option.type] | |
| res1: String = Option's kind is * -> *. | |
| This is a type constructor: a 1st-order-kinded type. Option[A] | |
| scala> kind[Either.type] | |
| res2: String = Either's kind is * -> * -> *. | |
| This is a type constructor: a 1st-order-kinded type. Either[L, R] | |
| scala> kind[Equal.type] | |
| res3: String = Equal's kind is * -> *. | |
| This is a type constructor: a 1st-order-kinded type. Equal[A] | |
| scala> kind[Functor.type] | |
| res4: String = Functor's kind is (* -> *) -> *. | |
| This is a type constructor that takes type constructor(s): a higher-kinded type. Functor[F[_]] | |
| */ | |
| def testFunctor() { | |
| /* | |
| Implicites dans le scope : | |
| implicit def ToFunctorOpsUnapply[FA](v: FA)(implicit F0: Unapply[Functor, FA]) = | |
| new FunctorOps[F0.M,F0.A] { def self = F0(v); implicit def F: Functor[F0.M] = F0.TC } | |
| implicit def ToFunctorOps[F[_],A](v: F[A])(implicit F0: Functor[F]) = | |
| new FunctorOps[F,A] { def self = v; implicit def F: Functor[F] = F0 } | |
| implicit def ToLiftV[F[_], A, B](v: A => B) = new LiftV[F, A, B] { def self = v } | |
| implicit def ToFunctorIdV[A](v: A) = new FunctorIdV[A] { def self = v } | |
| */ | |
| import syntax.functor._ | |
| // la classe Tuple de base n'a pas de methode map | |
| { | |
| /* | |
| scalaz/std/Tuple.scala : | |
| ------------------------------ | |
| private[scalaz] trait Tuple3Functor[A1, A2] extends Traverse[({type f[x] = (A1, A2, x)})#f] { | |
| override def map[A, B](fa: (A1, A2, A))(f: A => B) = | |
| (fa._1, fa._2, f(fa._3)) | |
| def traverseImpl[G[_], A, B](fa: (A1, A2, A))(f: A => G[B])(implicit G: Applicative[G]) = | |
| G.map(f(fa._3))((fa._1, fa._2, _)) | |
| } | |
| */ | |
| import std.tuple._ | |
| val t = (1, 2, 3) map { 1 + _ } | |
| println(t) // affiche (1, 2, 4) (fa._1, fa._2, f(fa._3)) | |
| } | |
| { | |
| // Composition | |
| // ---------------- | |
| // import functor instances | |
| import std.option._ | |
| /* | |
| scalaz/std/List.scala : | |
| ------------------------------ | |
| … | |
| // Traverse is a functor | |
| trait ListInstances extends ListInstances0 { | |
| // Le functor implicit | |
| implicit val listInstance = new Traverse[List] with MonadPlus[List] with Each[List] with Index[List] with Length[List] with Zip[List] with Unzip[List] with IsEmpty[List] { | |
| … | |
| object list extends ListInstances with ListFunctions { | |
| object listSyntax extends scalaz.syntax.std.ToListOps | |
| } | |
| … | |
| */ | |
| import std.list._ | |
| /* | |
| scalaz/Functor.scala : | |
| ------------------------------ | |
| // The composition of Functors `F` and `G`, `[x]F[G[x]]`, is a Functor | |
| def compose[G[_]](implicit G0: Functor[G]): Functor[({type λ[α] = F[G[α]]})#λ] = new CompositionFunctor[F, G] { | |
| implicit def F = self | |
| implicit def G = G0 | |
| } | |
| … | |
| object Functor { | |
| @inline def apply[F[_]](implicit F: Functor[F]): Functor[F] = F | |
| } | |
| scalaz/Composition.scala : | |
| ------------------------------ | |
| private[scalaz] trait CompositionFunctor[F[_], G[_]] extends Functor[({type λ[α] = F[G[α]]})#λ] { | |
| implicit def F: Functor[F] | |
| implicit def G: Functor[G] | |
| override def map[A, B](fga: F[G[A]])(f: A => B): F[G[B]] = F(fga)(ga => G(ga)(f)) | |
| } | |
| Functor[List] compose Functor[Option] == | |
| Functor[List].apply[List[_]](listInstance) compose Functor[Option].apply[Option[_]](optionInstance) == | |
| listInstance compose optionInstance | |
| In repl : | |
| scala> Functor[List] compose Functor[Option] | |
| res1: scalaz.Functor[[α]List[Option[α]]] = scalaz.Functor$$anon$1@598e89f5 | |
| scala> :t res1 | |
| scalaz.Functor[[α]List[Option[α]]] | |
| */ | |
| val compose1 = Functor[List] compose Functor[Option] // scalaz.Functor[[α]List[Option[α]]] | |
| /* | |
| map[Int, Double](fga: List[Option[Int]])(f: Int => Double): List[Option[Double]] == | |
| listInstance.apply(fga)(ga => optionInstance.apply(ga)(f)) == | |
| listInstance.map(fga)(ga => optionInstance.map(ga)(f)) == | |
| listInstance.traversal[Id](Id.id).run(fga)(ga => ga map f) == | |
| listInstance.traverseImpl[Id,Int,Double](fga)(ga => ga map f)(Id.id) == | |
| DList.fromList(fga).foldr(Id.id.point(Option[Double]())) { | |
| (ga, fbs) => Id.id.apply2(ga => ga map f, fbs)(_ :: _) | |
| } | |
| == | |
| DList.fromList(fga: List[Option[Int]]).foldr(List[Option[Double]]()) { | |
| (ga, fbs) => ap(fbs)(map(ga => ga map f)((_ :: _).curried)) | |
| } | |
| */ | |
| val fga = List(Some(1), None, Some(3)) | |
| val transfo: Int => Double = _ / 2.0 | |
| println(compose1.map(fga)(transfo)) // affiche List(Some(0.5), None, Some(1.5)) | |
| println(listInstance.map(fga)(ga => optionInstance.apply(ga)(transfo))) // affiche List(Some(0.5), None, Some(1.5)) | |
| { | |
| import Id.Id | |
| println(listInstance.traverseImpl[Id,Option[Int],Option[Double]](fga)(ga => ga map transfo)(Id.id)) // affiche List(Some(0.5), None, Some(1.5)) | |
| } | |
| println(intersperse(List(Some(1), Some(2), Some(3)), None)) // List(Some(1), None, Some(2), None, Some(3)) | |
| println(toNel(List(Some(1), None, Some(3)))) // affiche Some(NonEmptyList(Some(1), None, Some(3))) | |
| // Product | |
| // --------------------- | |
| /* | |
| private[scalaz] trait ProductFunctor[F[_], G[_]] extends Functor[({type λ[α] = (F[α], G[α])})#λ] { | |
| implicit def F: Functor[F] | |
| implicit def G: Functor[G] | |
| override def map[A, B](fa: (F[A], G[A]))(f: A => B): (F[B], G[B]) = (F.map(fa._1)(f), G.map(fa._2)(f)) | |
| } | |
| */ | |
| val product1 = Functor[List] product Functor[Option] // scalaz.Functor[[α](List[α], Option[α])] | |
| println(product1.map((List(1, 2, 3), Some(4)))(_.toString + " titi ")) // affiche (List(1 titi , 2 titi , 3 titi ),Some(4 titi )) | |
| val product2 = compose1 product Functor[Option] // scalaz.Functor[[α](List[Option[α]], Option[α])] | |
| println(product2.map((List(Some(1), Some(2), Some(3), None), Some(4)))(_.toString + " titi ")) // affiche (List(Some(1 titi ), Some(2 titi ), Some(3 titi ), None),Some(4 titi )) | |
| // Lift | |
| // --------------------- | |
| val lifted = product2.lift(transfo) // ((List[Option[Int]], Option[Int])) => (List[Option[Double]], Option[Double]) | |
| println(lifted((List(Some(1), Some(2), Some(3), None), Some(4)))) // (List(Some(0.5), Some(1.0), Some(1.5), None),Some(2.0)) | |
| // strengthL | |
| // --------------------- | |
| // compose1 = scalaz.Functor[[α]List[Option[α]]] | |
| println(compose1.strengthL(111, fga)) // List(Some((111,1)), None, Some((111,3))) | |
| } | |
| { | |
| import std.list._ | |
| import std.option._ | |
| // mapply | |
| // --------------------- | |
| val transfoA: Int => Double = _ / 2.0 | |
| val transfoB: Int => Double = _ + 1 | |
| val transfoC: Int => Double = _ * 2 | |
| val functions = List(transfoA, transfoB, transfoC) | |
| println(Functor[List].mapply(10)(functions)) // List[Double] = List(5.0, 11.0, 20.0) | |
| // void | |
| // --------------------- | |
| println((Functor[List] compose Functor[Option]).void(List(Some(1), None, Some(3)))) // List(Some(()), None, Some(())) | |
| println((Functor[List].compose[Option]).void(List(Some(1), None, Some(3)))) // List(Some(()), None, Some(())) | |
| } | |
| { | |
| // avec un implicit | |
| import std.list._ | |
| import std.option._ | |
| import syntax.functor._ | |
| implicit val mine = Functor[List] compose Functor[Option] | |
| /* | |
| <dobblego> yeah it will always use Functor[List] | |
| <dobblego> notice that Functor[List ∘ Option] is actually an inline type-alias | |
| <dobblego> so you could wrap List ∘ Option or use the existing one | |
| <dobblego> I don't know of a way to easily get your desired behaviour with the raw functor composition | |
| */ | |
| println(List(Some(1), None, Some(3)).void) // => problem : List((), (), ()) | |
| } | |
| { | |
| import std.list._ | |
| import std.option._ | |
| import syntax.functor._ | |
| type ListOption[α] = ({type λ[α] = List[Option[α]]})#λ[α] | |
| //scalaz.Functor[[α]List[Option[α]]] | |
| implicit val mine: Functor[ListOption] = Functor[List] compose Functor[Option] | |
| println(List(Some(1), None, Some(3)).void) // => non plus : List((), (), ()) | |
| } | |
| } | |
| /* | |
| [[scalaz.Applicative]] without `point`. | |
| nouvelle méthode : | |
| def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B] | |
| comparée avec : | |
| def map[A, B](fa: F[A])(f: A => B): F[B] | |
| pour `ap` fa est call by name | |
| ap equivaut à `<*>` | |
| */ | |
| def testApply() { | |
| import syntax.apply._ | |
| import std.option._ | |
| import std.list._ | |
| /* | |
| def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B] | |
| final def <*>[B](f: F[A => B]): F[B] = F.ap(self)(f) | |
| F : Apply[Option] | |
| scalaz/std/Option.scala : | |
| ------------------------------ | |
| trait OptionInstances extends OptionInstances0 { | |
| implicit val optionInstance = new Traverse[Option] with MonadPlus[Option] with Each[Option] with Index[Option] with Length[Option] with Cozip[Option] with Zip[Option] with Unzip[Option] with IsEmpty[Option] { | |
| … | |
| override def ap[A, B](fa: => Option[A])(f: => Option[A => B]) = f match { | |
| case Some(f) => fa match { | |
| case Some(x) => Some(f(x)) | |
| case None => None | |
| } | |
| case None => None | |
| } | |
| */ | |
| println(some(9) <*> some((_: Int) + 3)) // affiche Some(12) | |
| println(some(9) <*> some((_: Int) + " toto ")) // affiche Some(9 toto ) | |
| /* | |
| scalaz/Bind.scala : | |
| ------------------------------ | |
| trait Bind[F[_]] extends Apply[F] { self => | |
| //// | |
| /** Equivalent to `join(map(fa)(f))`. */ | |
| def bind[A, B](fa: F[A])(f: A => F[B]): F[B] | |
| override def ap[A, B](fa: => F[A])(f: => F[A => B]): F[B] = bind(f)(f => map(fa)(f)) | |
| … | |
| } | |
| scalaz/std/List.scala : | |
| ------------------------------ | |
| … | |
| def bind[A, B](fa: List[A])(f: A => List[B]) = fa flatMap f | |
| … | |
| */ | |
| println(List(9, 10) <*> List((_: Int) + 3)) // List[Int] = List(12, 13) | |
| println(Apply[Option].ap2(some("1"), some("2"))(some((_: String) + (_: String)))) // Some(12) | |
| // cf. apply2 | |
| println(^(List(9, 10), List(11, 12))((a: Int, b: Int) => a.toString + "-" + b.toString)) // List(9-11, 9-12, 10-11, 10-12) | |
| Apply[List].compose[Option].ap(List(Some(1), None, Some(3)))(List(Some((_: Int) + 3))) // List(Some(4), None, Some(6)) | |
| } | |
| /* | |
| http://www.soi.city.ac.uk/~ross/papers/Applicative.pdf | |
| Applicative functors — an abstract characterisation of an applicative style of effectful programming, | |
| weaker than Monads and hence more widespread. | |
| From Haskell : | |
| Recall that Functor allows us to lift a “normal” function to a function on computational contexts. | |
| But fmap (map in Scala) doesn’t allow us to apply a function which is itself in a context to a value in a context. | |
| Applicative gives us just such a tool, (<*>). | |
| It also provides a method, pure, for embedding values in a default, “effect free” context. | |
| Laws : | |
| - The identity law: | |
| pure id <*> v = v | |
| - Homomorphism: | |
| pure f <*> pure x = pure (f x) | |
| Intuitively, applying a non-effectful function to a non-effectful argument in an effectful context is the same as | |
| just applying the function to the argument and then injecting the result into the context with pure. | |
| - Interchange: | |
| u <*> pure y = pure ($ y) <*> u | |
| Intuitively, this says that when evaluating the application of an effectful function to a pure argument, | |
| the order in which we evaluate the function and its argument doesn't matter. | |
| - Composition: | |
| u <*> (v <*> w) = pure (.) <*> u <*> v <*> w | |
| This one is the trickiest law to gain intuition for. In some sense it is expressing a sort of associativity | |
| property of (<*>). The reader may wish to simply convince themselves that this law is type-correct. | |
| scalaz/Applicative.scala : | |
| ------------------------------ | |
| * Applicative Functor, described in [[http://www.soi.city.ac.uk/~ross/papers/Applicative.html Applicative Programming with Effects]] | |
| * | |
| * Whereas a [[scalaz.Functor]] allows application of a pure function to a value in a context, an Applicative | |
| * also allows application of a function in a context to a value in a context (`ap`). | |
| * | |
| * It follows that a pure function can be applied to arguments in a context. (See `map2`, `map3`, ... ) | |
| * | |
| * Applicative instances come in a few flavours: | |
| * - All [[scalaz.Monad]]s are also `Applicative` | |
| * - Any [[scalaz.Monoid]] can be treated as an Applicative (see [[scalaz.Monoid]]#applicative) | |
| * - Zipping together corresponding elements of Naperian data structures (those of of a fixed, possibly infinite shape) | |
| trait Applicative[F[_]] extends Apply[F] { self => | |
| //// | |
| def point[A](a: => A): F[A] | |
| // alias for point | |
| def pure[A](a: => A): F[A] = point(a) | |
| // derived functions | |
| override def map[A, B](fa: F[A])(f: A => B): F[B] = | |
| ap(fa)(point(f)) | |
| override def apply2[A, B, C](fa: => F[A], fb: => F[B])(f: (A, B) => C): F[C] = | |
| ap2(fa, fb)(point(f)) | |
| … | |
| scalaz/std/List.scala : | |
| ------------------------------ | |
| … | |
| //It also provides a method, pure, for embedding values in a default, “effect free” context. | |
| //pure takes a value of any type a, and returns a context/container of type f a. The intention is that pure creates some | |
| //sort of “default” container or “effect free” context. In fact, the behavior of pure is quite constrained by the laws | |
| //it should satisfy in conjunction with (<*>). Usually, for a given implementation of (<*>) there is only one possible | |
| //implementation of pure. | |
| def point[A](a: => A) = scala.List(a) | |
| … | |
| */ | |
| def testApplicative() { | |
| import syntax.applicative._ | |
| { | |
| import std.list._ | |
| import std.option._ | |
| import std.option.optionSyntax._ | |
| import std.function._ | |
| /* | |
| //// | |
| implicit def ApplicativeIdV[A](v: => A) = new ApplicativeIdV[A] { | |
| lazy val self = v | |
| } | |
| trait ApplicativeIdV[A] extends Ops[A] { | |
| def point[F[_] : Applicative]: F[A] = Applicative[F].point(self) | |
| def pure[F[_] : Applicative]: F[A] = Applicative[F].point(self) | |
| def η[F[_] : Applicative]: F[A] = Applicative[F].point(self) | |
| } //// | |
| */ | |
| println(1.point[List]) // List(1) | |
| /* | |
| cool about the fact that constructor is abstracted out. | |
| scalaz/syntax/std/OptionIdOps.scala : | |
| ------------------------------------- | |
| trait OptionIdOps[A] extends Ops[A] { | |
| def some: Option[A] = Some(self) | |
| } | |
| trait ToOptionIdOps { | |
| implicit def ToOptionIdOps[A](a: A) = new OptionIdOps[A] { def self = a } | |
| } | |
| */ | |
| println(1.point[List] map {_ + 2}) // List(3) | |
| println(9.some <*> {(_: Int) + 3}.some) // Some(12) | |
| println(1.some <* 2.some) // Some(1) | |
| println(none <* 2.some) // None | |
| println(1.some *> 2.some) // Some(2) | |
| println(none *> 2.some) // None | |
| /* | |
| 3.some <*> { 9.some <*> {(_: Int) + (_: Int)}.curried.some } == | |
| 3.some <*> {(_: Int) + 9}.some | |
| */ | |
| println(3.some <*> { 9.some <*> {(_: Int) + (_: Int)}.curried.some }) // Some(12) | |
| println(3.some <*> {(_: Int) + 9}.some) // Some(12) | |
| println(^(3.some, 5.some) {_ + _}) // Some(8) | |
| println(^(3.some, none: Option[Int]) {_ + _}) // None | |
| /* | |
| The new ^(f1, f2) {...} style is not without the problem though. It doesn’t seem to handle Applicatives that | |
| takes two type parameters like Function1, Writer, and Validation. There’s another way called Applicative Builder, | |
| which apparently was the way it worked in Scalaz 6, got deprecated in M3, but will be vindicated again | |
| because of ^(f1, f2) {...}’s issues. | |
| scalaz/syntax/ApplySyntax.scala : | |
| ------------------------------ | |
| final def |@|[B](fb: F[B]) = new ApplicativeBuilder[F, A, B] { | |
| val a: F[A] = self | |
| val b: F[B] = fb | |
| } | |
| Here’s how it looks: | |
| */ | |
| println((3.some |@| 5.some) {_ + _}) // Some(8) | |
| println(List(9, 10) <*> List((_: Int) + 3)) // List[Int] = List(12, 13) | |
| println(List(9, 10) <*> List((_: Int) + 3, (_: Int) + 100)) // List(12, 13, 109, 110) | |
| println(^(3.some, 5.some) {_ + _}) // Some(8) | |
| println((3.some |@| 5.some) {_ + _}) // Some(8) | |
| println(^(List(9, 10), List(11, 12))((a: Int, b: Int) => a.toString + "-" + b.toString)) // List(9-11, 9-12, 10-11, 10-12) | |
| println((List(9, 10) |@| List(11, 12))((a: Int, b: Int) => a.toString + "-" + b.toString)) // List(9-11, 9-12, 10-11, 10-12) | |
| println((List(9, 10) |@| List(11, 12) |@| List(13, 14))((_, _, _))) // List((9,11,13), (9,11,14), (9,12,13), (9,12,14), (10,11,13), (10,11,14), (10,12,13), (10,12,14)) | |
| // List[F[A]] => F[List[A]] | |
| def sequenceA[F[_]: Applicative, A](list: List[F[A]]): F[List[A]] = list match { | |
| case Nil => (Nil: List[A]).point[F] | |
| case x :: xs => (x |@| sequenceA(xs)) {_ :: _} | |
| } | |
| println(sequenceA(List(1.some, 2.some))) // Some(List(1, 2)) | |
| println(sequenceA(List(3.some, none, 1.some))) // None | |
| println(sequenceA(List(List(1, 2, 3), List(4, 5, 6)))) // List(List(1, 4), List(1, 5), List(1, 6), List(2, 4), List(2, 5), List(2, 6), List(3, 4), List(3, 5), List(3, 6)) | |
| // intellij a du mal | |
| type Function1Int[A] = ({type l[A]=Function1[Int, A]})#l[A] | |
| val s = sequenceA(List((_: Int) + 3, (_: Int) + 2, (_: Int) + 1): List[Function1Int[Int]]) | |
| println(s(3)) // List(6, 5, 4) | |
| } | |
| } | |
| /* | |
| LYAHFGG: | |
| It seems that both * together with 1 and ++ along with [] share some common properties: - The function takes two | |
| parameters. - The parameters and the returned value have the same type. - There exists such a value that doesn’t | |
| change other values when used with the binary function. | |
| It doesn’t matter if we do (3 * 4) * 5 or 3 * (4 * 5). Either way, the result is 60. The same goes for ++. … | |
| We call this property associativity. * is associative, and so is ++, but -, for example, is not. | |
| scala> (3 * 2) * (8 * 5) assert_=== 3 * (2 * (8 * 5)) | |
| scala> List("la") ++ (List("di") ++ List("da")) assert_=== (List("la") ++ List("di")) ++ List("da") | |
| A monoid is when you have an associative binary function and a value which acts as an identity with respect to that | |
| function. | |
| // An associative binary operation, circumscribed by type and the | |
| // semigroup laws. Unlike [[scalaz.Monoid]], there is not necessarily | |
| // a zero. | |
| trait Semigroup[A] { self => | |
| def append(a1: A, a2: => A): A | |
| ... | |
| } | |
| // Provides an identity element (`zero`) to the binary `append` | |
| // operation in [[scalaz.Semigroup]], subject to the monoid laws. | |
| // | |
| // Example instances: | |
| // - `Monoid[Int]`: `zero` and `append` are `0` and `Int#+` respectively | |
| // - `Monoid[List[A]]`: `zero` and `append` are `Nil` and `List#++` respectively | |
| // LYAHFGG: | |
| // | |
| // mempty represents the identity value for a particular monoid. | |
| // | |
| // Scalaz calls this zero instead. | |
| trait Monoid[A] extends Semigroup[A] { self => | |
| //// | |
| // The identity element for `append`. | |
| def zero: A | |
| ... | |
| } | |
| // We have mappend, which, as you’ve probably guessed, is the binary function. It takes two values of the | |
| // same type and returns a | |
| // value of that type as well. | |
| trait SemigroupOps[A] extends Ops[A] { | |
| final def |+|(other: => A): A = A.append(self, other) | |
| final def mappend(other: => A): A = A.append(self, other) | |
| final def ⊹(other: => A): A = A.append(self, other) | |
| } | |
| cf. http://eed3si9n.com/learning-scalaz/Monoid.html | |
| Semigroup and Monoid as a way of abstracting binary operations over various types. | |
| */ | |
| def testMonoid() { | |
| { | |
| import syntax.semigroup._ | |
| import syntax.order._ | |
| import std.list._ | |
| import std.string._ | |
| import std.option._ | |
| import std.option.optionSyntax._ | |
| println(List(1, 2, 3) |+| List(4, 5, 6)) // List(1, 2, 3, 4, 5, 6) | |
| println("one" |+| "two") // onetwo | |
| println(Monoid[List[Int]].zero) // List() | |
| println(Monoid[String].zero) // "" | |
| def lengthCompare(lhs: String, rhs: String): Ordering = | |
| (lhs.length ?|? rhs.length) |+| (lhs ?|? rhs) | |
| println(lengthCompare("zen", "ants")) // LT | |
| println(lengthCompare("zen", "ant")) // GT | |
| // cf. http://eed3si9n.com/learning-scalaz/Option+as+Monoid.html | |
| println((none: Option[String]) |+| "andy".some) // Some(andy) | |
| println("toto".some |+| "andy".some) // Some(totoandy) | |
| } | |
| } | |
| /* | |
| From Haskell : | |
| Monads are a natural extension applicative functors, and they provide a solution to the following problem: | |
| If we have a value with context, m a, how do we apply it to a function that takes a normal a | |
| and returns a value with a context. | |
| flatMap | |
| trait Monad[F[_]] extends Applicative[F] with Bind[F] { self => | |
| //// | |
| } | |
| trait Bind[F[_]] extends Apply[F] { self => | |
| // Equivalent to `join(map(fa)(f))`. join <=> flatten | |
| def bind[A, B](fa: F[A])(f: A => F[B]): F[B] | |
| } | |
| // Wraps a value `self` and provides methods related to `Bind` | |
| trait BindOps[F[_],A] extends Ops[F[A]] { | |
| implicit def F: Bind[F] | |
| //// | |
| import Liskov.<~< | |
| def flatMap[B](f: A => F[B]) = F.bind(self)(f) | |
| def >>=[B](f: A => F[B]) = F.bind(self)(f) | |
| def ∗[B](f: A => F[B]) = F.bind(self)(f) | |
| def join[B](implicit ev: A <~< F[B]): F[B] = F.bind(self)(ev(_)) | |
| def μ[B](implicit ev: A <~< F[B]): F[B] = F.bind(self)(ev(_)) | |
| def >>[B](b: F[B]): F[B] = F.bind(self)(_ => b) | |
| def ifM[B](ifTrue: => F[B], ifFalse: => F[B])(implicit ev: A <~< Boolean): F[B] = { | |
| val value: F[Boolean] = Liskov.co[F, A, Boolean](ev)(self) | |
| F.ifM(value, ifTrue, ifFalse) | |
| } | |
| //// | |
| } | |
| */ | |
| def testMonad() { | |
| import syntax.monad._ | |
| import std.list._ | |
| import std.string._ | |
| import std.option._ | |
| import std.option.optionSyntax._ | |
| println(Monad[Option].point("WHAT")) // Some(WHAT) | |
| println(9.some flatMap { x => Monad[Option].point(x * 10) }) // Some(90) | |
| /* | |
| Let’s say that [Pierre] keeps his balance if the number of birds on the left side of the pole and on the right side | |
| of the pole is within three. So if there’s one bird on the right side and four birds on the left side, he’s okay. | |
| But if a fifth bird lands on the left side, then he loses his balance and takes a dive. | |
| We may also devise a function that ignores the current number of birds on the balancing pole and just | |
| makes Pierre slip and fall. We can call it banana. | |
| */ | |
| type Birds = Int | |
| case class Pole(left: Birds, right: Birds) { | |
| def landLeft(n: Birds): Option[Pole] = { | |
| println("landLeft :" + n) | |
| if (math.abs((left + n) - right) < 4) copy(left = left + n).some | |
| else none | |
| } | |
| def landRight(n: Birds): Option[Pole] = { | |
| println("landRight :" + n) | |
| if (math.abs(left - (right + n)) < 4) copy(right = right + n).some | |
| else none | |
| } | |
| def banana: Option[Pole] = { | |
| println("banana :") | |
| none | |
| } | |
| } | |
| // >>= is flatMap | |
| // prints | |
| /* | |
| landLeft :1 | |
| landRight :4 | |
| landLeft :-1 | |
| None | |
| */ | |
| println(Monad[Option].point(Pole(0, 0)) >>= {_.landLeft(1)} >>= {_.landRight(4)} >>= {_.landLeft(-1)} /* fails fast */ >>= {_.landRight(-2)} >>= {_.landRight(-2)}) | |
| // Option is already a monad | |
| // prints | |
| /* | |
| landLeft :1 | |
| landRight :4 | |
| landLeft :-1 | |
| None | |
| */ | |
| println(for { | |
| p1 <- Pole(0, 0).landLeft(1) | |
| p2 <- p1.landRight(4) | |
| p3 <- p2.landLeft(-1) // fails here | |
| p4 <- p3.landRight(-2) | |
| p5 <- p4.landRight(-2) | |
| } yield p5) | |
| // None | |
| println(for { | |
| start <- Monad[Option].point(Pole(0, 0)) | |
| first <- start.landLeft(2) | |
| _ <- (none: Option[Pole]) | |
| second <- first.landRight(2) | |
| third <- second.landLeft(1) | |
| } yield third) | |
| // Instead of making functions that ignore their input and just return a predetermined monadic value, | |
| // we can use the >> function. | |
| /* | |
| scala> (none: Option[Int]) >> 3.some // restart with none | |
| res25: Option[Int] = None | |
| scala> 3.some >> 4.some // ignore 3 | |
| res26: Option[Int] = Some(4) | |
| scala> 3.some >> (none: Option[Int]) // ignore 3 | |
| res27: Option[Int] = None | |
| */ | |
| // plantage de : cf. http://eed3si9n.com/learning-scalaz/Walk+the+line.html | |
| // Monad[Option].point(Pole(0, 0)) >>= {_.landLeft(1)} >> (none: Option[Pole]) >>= {_.landRight(1)} | |
| // car the operator >> precedence. | |
| println(Monad[Option].point(Pole(0, 0)).>>=({_.landLeft(1)}).>>(none: Option[Pole]).>>=({_.landRight(1)})) | |
| // Or recognize the precedence issue and place parens around just the right place: | |
| println((Monad[Option].point(Pole(0, 0)) >>= {_.landLeft(1)}) >> (none: Option[Pole]) >>= {_.landRight(1)}) | |
| } | |
| /* | |
| Whereas the Maybe monad is for values with an added context of failure, and the list monad is for nondeterministic | |
| values, Writer monad is for values that have another value attached that acts as a sort of log value. | |
| cf. http://eed3si9n.com/learning-scalaz/Writer.html | |
| sealed trait WriterT[F[+_], +W, +A] { self => | |
| val run: F[(W, A)] | |
| def written(implicit F: Functor[F]): F[W] = | |
| F.map(run)(_._1) | |
| def value(implicit F: Functor[F]): F[A] = | |
| F.map(run)(_._2) | |
| } | |
| trait WriterTFunctions { | |
| def writerT[F[+_], W, A](v: F[(W, A)]): WriterT[F, W, A] = new WriterT[F, W, A] { | |
| val run = v | |
| } | |
| import StoreT._ | |
| def writer[W, A](v: (W, A)): Writer[W, A] = | |
| writerT[Id, W, A](v) | |
| def tell[W](w: W): Writer[W, Unit] = writer(w -> ()) | |
| def put[F[+_], W, A](value: F[A])(w: W)(implicit F: Functor[F]): WriterT[F, W, A] = | |
| WriterT(F.map(value)(a => (w, a))) | |
| /** Puts the written value that is produced by applying the given function into a writer transformer and associates with `value` */ | |
| def putWith[F[+_], W, A](value: F[A])(w: A => W)(implicit F: Functor[F]): WriterT[F, W, A] = | |
| WriterT(F.map(value)(a => (w(a), a))) | |
| } | |
| trait WriterOps[A] extends Ops[A] { | |
| def set[W](w: W): Writer[W, A] = WriterT.writer(w -> self) | |
| def tell: Writer[A, Unit] = WriterT.tell(self) | |
| } | |
| scalaz/package.scala : | |
| ------------------------------ | |
| type Writer[+W, +A] = WriterT[Id, W, A] | |
| type Unwriter[+W, +A] = UnwriterT[Id, W, A] | |
| */ | |
| def testWriterMonad() { | |
| import syntax.writer._ | |
| import syntax.show._ | |
| import std.vector._ | |
| import std.anyVal._ // default shows | |
| println(3.set("Smallish gang.")) //scalaz.WriterTFunctions$$anon$23@53e082bb | |
| println(3.set("Smallish gang.").run)// (Smallish gang.,3) | |
| println("something".tell) // scalaz.WriterTFunctions$$anon$23@38a6ee02 | |
| println("something".tell.run) // (String, Unit) = (something,()) | |
| def gcd(a: Int, b: Int): Writer[Vector[String], Int] = | |
| if (b == 0) for { | |
| _ <- Vector("Finished with " + a.shows).tell | |
| } yield a | |
| else for { | |
| _ <- Vector(a.shows + " mod " + b.shows + " = " + (a % b).shows).tell | |
| result <- gcd(b, a % b) | |
| } yield result | |
| println(gcd(8, 3).run) // (Vector(8 mod 3 = 2, 3 mod 2 = 1, 2 mod 1 = 0, Finished with 1),1) | |
| def testA: Writer[Vector[String], Int] = for { | |
| _ <- Vector("a").tell | |
| _ <- Vector("b").tell | |
| _ <- Vector("c").tell | |
| } yield 1000 | |
| println(testA.run) // (Vector(a, b, c),1000) | |
| def invokeService(a: Int): Writer[Vector[String], Int] = for { | |
| _ <- Vector("Début invokeService").tell | |
| } yield 1000 + a | |
| def testB: Writer[Vector[String], Int] = for { | |
| _ <- Vector("Début testB").tell | |
| _ <- Vector("b").tell | |
| b <- invokeService(4) | |
| _ <- Vector("c").tell | |
| _ <- Vector("Fin").tell | |
| } yield b | |
| println(testB.run) // (Vector(a, b, c),1000) | |
| } | |
| /* | |
| import scalaz._, Scalaz._ | |
| object RWSExample extends App { | |
| case class Config(port: Int) | |
| def log[R, S](msg: String): ReaderWriterState[R, List[String], S, Unit] = | |
| ReaderWriterStateT { | |
| case (r, s) => (msg.format(r, s) :: Nil, (), s).point[Identity] | |
| } | |
| def invokeService: ReaderWriterState[Config, List[String], Int, Int] = | |
| ReaderWriterStateT { | |
| case (cfg, invocationCount) => ( | |
| List("Invoking service with port " + cfg.port), | |
| scala.util.Random.nextInt(100), | |
| invocationCount + 1 | |
| ).point[Identity] | |
| } | |
| val program: RWS[Config, List[String], Int, Int] = for { | |
| _ <- log("Start - r: %s, s: %s") | |
| res <- invokeService | |
| _ <- log("Between - r: %s, s: %s") | |
| _ <- invokeService | |
| _ <- log("Done - r: %s, s: %s") | |
| } yield res | |
| val Need(logMessages, result, invocationCount) = program run (Config(443), 0) | |
| println("Result: " + result) | |
| println("Service invocations: " + invocationCount) | |
| println("Log: %n%s".format(logMessages.mkString("\t", "%n\t".format(), ""))) | |
| } | |
| */ | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment