Last active
October 25, 2016 01:32
-
-
Save krishnanraman/4759672 to your computer and use it in GitHub Desktop.
Tony Morris class
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
// And by the way, please feel free to contribute, correct errors, etc! | |
trait Functor[F[_]] { | |
def fmap[A, B](f: A => B): F[A] => F[B] | |
} | |
object Functor { | |
val ListFunctor: Functor[List] = | |
new Functor[List] { | |
def fmap[A, B](f: A => B) = | |
_ map f | |
} | |
val IntReaderFunctor: Functor[IntReader] = | |
new Functor[IntReader] { | |
def fmap[A, B](f: A => B) = | |
ir => IntReader(f compose ir.run) | |
} | |
val OptionFunctor: Functor[Option] = | |
new Functor[Option] { | |
def fmap[A, B](f: A => B) = | |
_ map f | |
} | |
} | |
trait Apply[F[_]] extends Functor[F] { | |
def ap[A, B](f: F[A => B]): F[A] => F[B] | |
} | |
trait Applicative[F[_]] extends Apply[F] { | |
def insert[A](a: A): F[A] | |
override def fmap[A, B](f: A => B) = | |
ap(insert(f)) | |
} | |
trait Cobind[F[_]] extends Functor[F] { | |
def cobind[A, B](f: F[A] => B): F[A] => F[B] | |
} | |
object Cobind { | |
val OptionCobind: Cobind[Option] = | |
new Cobind[Option] { | |
def fmap[A, B](f: A => B) = | |
_ map f | |
def cobind[A, B](f: Option[A] => B) = | |
x => x map (_ => f(x)) | |
} | |
val ListCobind: Cobind[List] = | |
new Cobind[List] { | |
def fmap[A, B](f: A => B) = | |
_ map f | |
def cobind[A, B](f: List[A] => B) = { | |
case Nil => Nil | |
case l@(_::t) => f(l) :: cobind(f)(t) | |
} | |
} | |
} | |
trait Comonad[F[_]] extends Cobind[F] { | |
def extract[A](a: F[A]): A | |
override def fmap[A, B](f: A => B) = | |
cobind(x => f(extract(x))) | |
} | |
object Comonad { | |
val ListZipperComonad: Comonad[ListZipper] = | |
new Comonad[ListZipper] { | |
def extract[A](x: ListZipper[A]) = | |
x.focus | |
// utility | |
def unfoldr[X, Y](f: Y => Option[(X, Y)], y: Y): List[X] = | |
f(y) match { | |
case None => Nil | |
case Some((x, yy)) => x :: unfoldr(f, yy) | |
} | |
def cobind[A, B](f: ListZipper[A] => B) = { | |
case z@ListZipper(l, x, r) => | |
ListZipper(unfoldr((_: ListZipper[A]).moveLeft map (q => (f(q), q)), z), f(z), unfoldr((_: ListZipper[A]).moveRight map (q => (f(q), q)), z)) | |
} | |
} | |
} | |
trait Bind[F[_]] extends Apply[F] { | |
def bind[A, B](f: A => F[B]): F[A] => F[B] | |
def flatten[A](x: F[F[A]]): F[A] = | |
bind(identity[F[A]])(x) | |
} | |
trait Monad[F[_]] extends Bind[F] with Applicative[F] { | |
override def ap[A, B](f: F[A => B]) = | |
(fa: F[A]) => bind((ff: A => B) => bind((a: A) => insert(ff(a)))(fa))(f) | |
// http://etorreborre.blogspot.com.au/2011/06/essence-of-iterator-pattern.html | |
// related to traverse below | |
def sequence[A](x: List[F[A]]): F[List[A]] = | |
x match { | |
case Nil => insert(Nil) | |
case h::t => bind((hh: A) => fmap((tt: List[A]) => hh::tt)(sequence(t)))(h) | |
} | |
def lift2[A, B, C](f: A => B => C): F[A] => F[B] => F[C] = | |
fa => fb => bind((a: A) => fmap[B,C]((b: B) => f(a)(b))(fb))(fa) | |
// http://etorreborre.blogspot.com.au/2011/06/essence-of-iterator-pattern.html | |
// related to sequence above | |
def traverse[A, B](f: A => F[B], x: List[A]): F[List[B]] = | |
sequence(x map f) | |
def replicate[A](n: Int, x: F[A]): F[List[A]] = | |
sequence(List.fill(n)(x)) | |
def filter[A](p: A => F[Boolean], x: List[A]): F[List[A]] = | |
x match { | |
case Nil => insert(Nil) | |
case h::t => bind((b: Boolean) => (if(b) fmap(h::(_: List[A])) else identity[F[List[A]]](_))(filter(p, t)))(p(h)) | |
} | |
} | |
object Monad { | |
val IntReaderWriterMonad: Monad[IntReaderWriter] = | |
new Monad [IntReaderWriter] { | |
def bind[A, B](f: A => IntReaderWriter[B]): | |
IntReaderWriter[A] => IntReaderWriter[B] = | |
rwa => IntReaderWriter(i => { | |
val (log1, a) = rwa.run(i) | |
val (log2, b) = f(a).run(i) | |
(log1 ++ log2, b) | |
}) | |
def insert[A](a: A) = | |
IntReaderWriter( _ => (Nil,a)) | |
} | |
val IdMonad: Monad[Id] = | |
new Monad[Id] { | |
def bind[A, B](f: A => Id[B]): Id[A] => Id[B] = | |
(x: Id[A]) => f(x.a) | |
def insert[A](a: A): Id[A] = | |
Id(a) | |
} | |
val ListMonad: Monad[List] = | |
new Monad[List] { | |
def bind[A, B](f: A => List[B]) = | |
(xs: List[A]) => xs match { | |
case Nil => Nil | |
case h :: t => f(h) ::: bind(f)(t) | |
} | |
def insert[A](a: A) = | |
List(a) | |
} | |
val OptionMonad: Monad[Option] = | |
new Monad[Option] { | |
def bind[A, B](f: A => Option[B]) = | |
(x: Option[A]) => x match { | |
case Some(a) => f(a) | |
case None => None | |
} | |
def insert[A](a: A) = | |
Option(a) | |
} | |
val IntReaderMonad: Monad[IntReader] = | |
new Monad[IntReader] { | |
def bind[A, B](f: A => IntReader[B]) = | |
x => IntReader(i => f(x run i) run i) | |
def insert[A](a: A) = | |
IntReader(_ => a) | |
} | |
val IntStateMonad: Monad[IntState] = | |
new Monad[IntState] { | |
def bind[A, B](f: A => IntState[B]) = | |
q => IntState[B](i => { | |
val (i2,a) = q.run(i) | |
f(a) run i2 | |
}) | |
def insert[A](a: A) = | |
IntState[A]((i: Int) => (i,a)) | |
} | |
val IntReaderOptionMonad: Monad[IntReaderOption] = | |
new Monad[IntReaderOption] { | |
def bind[A, B](f: A => IntReaderOption[B]) = | |
iro => IntReaderOption(i => (iro run i) match { | |
case Some(ii) => f(ii) run i | |
case None => None | |
}) | |
def insert[A](a: A) = | |
IntReaderOption(_ => OptionMonad.insert(a)) | |
} | |
val WriterMonad: Monad[Writer] = | |
new Monad[Writer] { | |
def bind[A, B](f: A => Writer[B]) = | |
x => { | |
val nw = f(x.a) | |
Writer(x.log ++ nw.log, nw.a) | |
} | |
def insert[A](a: A) = | |
Writer(Nil, a) | |
} | |
} | |
case class IntReader[A](run: Int => A) | |
case class Id[A](a: A) | |
case class IntState[A](run: Int => (Int, A)) | |
case class Writer[A](log: List[String], a: A) | |
case class IntReaderOption[A](run: Int => Option[A]) | |
case class ReaderWriter[A,B](run: A=>(List[String], B)) | |
case class IntReaderWriter[A](run: Int=>(List[String], A)) | |
case class ListZipper[A](left: List[A], focus: A, right: List[A]) { | |
def map[B](f: A => B): ListZipper[B] = | |
ListZipper(left map f, f(focus), right map f) | |
def moveLeft: Option[ListZipper[A]] = | |
left match { | |
case Nil => None | |
case h::t => Some(ListZipper(t, h, focus :: right)) | |
} | |
def moveRight: Option[ListZipper[A]] = | |
right match { | |
case Nil => None | |
case h::t => Some(ListZipper(focus :: left, h, t)) | |
} | |
} | |
object Main { | |
import Functor._ | |
import Monad._ | |
def main(args: Array[String]) { | |
val list = (1 to 9).toList | |
val r = ListFunctor.fmap[Int, Double](math.sin(_))(list) | |
println(r) | |
val list2 = List(Some(7), Some(8), Some(9)) | |
println(OptionMonad.sequence(list2)) | |
val list3 = List(IntReader(_+10), IntReader(_*20), IntReader(100-_)) | |
println(IntReaderMonad.sequence(list3) run 42) | |
} | |
} | |
/* | |
#!/bin/sh | |
TMP=/tmp | |
FILE=$TMP/jY5OglmAOC.scala | |
wget http://titanpad.com/ep/pad/export/jY5OglmAOC/latest?format=txt -q -O $FILE | |
scalac -d $TMP $FILE | |
scala -classpath $TMP Main | |
*/ | |
/** | |
* Tony Morris: IRc keeps netsplitting | |
19:15 Tony Morris: Yellow almost has a correct flatten (currently not type checking) | |
19:26 scroy: gah, that took forever | |
19:27 scroy: too much pressure! | |
19:28 Tony Morris: oh wait I told you a lie! | |
19:28 Tony Morris: f(ii): IntOptionReader[B] | |
19:28 Tony Morris: sorry! | |
19:29 Tony Morris: you were almost finished | |
19:30 Tony Morris: can't use OptionMonad to compose with the option monad :( | |
19:31 scroy: hm, so i guess insert is wrong too? | |
19:31 Tony Morris: insert is correct | |
19:31 Tony Morris: and f(ii) was on the right track | |
19:32 Tony Morris: actually, I think there is a way to write it with OptionMonad here, but by coincidence, or maybe I need to align the types properly | |
19:32 Tony Morris: who wants to trye sequence? | |
19:34 Tony Morris: I wish IRC would come back! | |
19:34 Tony Morris: currently when I run main, I get an explosion, because sequence is not done | |
19:35 vj: intreaderoption | |
19:35 vj: can you explain the bind | |
19:36 Tony Morris: it is combining the behaviour of both IntReader and Option | |
19:36 Tony Morris: IntReader pushes through a value (i) of the type Int | |
19:36 vj: ok | |
19:36 Tony Morris: Option "tries to keep alive" with Some | |
19:37 Tony Morris: and IntOptionReader does both of these together and is its own monad | |
19:37 unnamed: oh. yeah I get it. you need to pas in the ii to the f so they have access to it if there is Some | |
19:37 vj: ok | |
19:37 Tony Morris: Reader monad is useful for passing a read-only context around a program without having to explicitly do so | |
19:38 Tony Morris: you know, like "configuration" or something | |
19:38 scroy: so several bound Monads would push a single value through | |
19:38 David Tchepak: is flatten right? | |
19:38 Tony Morris: yep | |
19:38 unnamed: uh, so if I wanted, could I write ReaderWriter? I mean, theoretically. I'm not sure I can bust it out... | |
19:38 scroy: monads seem useful for implementing a compiler | |
19:38 Tony Morris: yes | |
19:39 David T: my scala is non-existent... why the "identity[F[A]]"? | |
19:39 Tony Morris: David: the id function is called identity in Scala and you need to help out the type-inferencer with an annotation | |
19:39 David T: oh right, i was mixing up identity with insert :$ | |
19:39 Tony Morris: anyone want to finish sequence? | |
19:40 David T: so bind(a => a) is no good? | |
19:40 Tony Morris: that will probably work too | |
19:41 unnamed: Is that close at all? for ReaderWriter class? | |
19:41 Tony Morris: yes that is Reader stacked on Writer | |
19:42 Tony Morris: but you are going to have a hard time because of parameterisation | |
19:42 Tony Morris: I suggest dropping the A and using something concrete like Int | |
19:43 Tony Morris: ready for sequence then? I was hoping for IRC to make the conclusion | |
19:44 vj: yep | |
19:47 Tony Morris: lost in braces again | |
19:47 Tony Morris: ok I will fill out sequence | |
19:47 Tony Morris: then make the conclusion | |
19:49 Tony Morris: bah brackets and things | |
19:49 David T: little help on lift2? | |
19:50 Tony Morris: do it | |
19:53 Tony Morris: I believe we have a winner | |
19:54 unnamed: ok, back. Can you let me know if my ReaderWriter is sort of on the right track? | |
19:55 Tony Morris: ReaderWriter is on the right track | |
19:56 Tony Morris: need insert | |
19:57 Tony Morris: OK I think we make the conclusion now right? | |
19:57 Tony Morris: what is the point of all this? | |
19:58 Tony Morris: let's make sure we are compiling first! | |
19:58 Tony Morris: OK compiling | |
19:58 Tony Morris: the point of all this is that we have: | |
19:59 Tony Morris: 1) many monad instances | |
19:59 Tony Morris: 1.1) Option, List, IntReader, etc etc | |
19:59 Tony Morris: 2) many monad libraries | |
19:59 Tony Morris: 2.1) sequence, lift2, etc etc | |
19:59 Tony Morris: So from here, we can ask: | |
19:59 Tony Morris: a) what other monads instances are there? | |
19:59 Tony Morris: b) what other monad libraries are there? | |
19:59 Tony Morris: c) and most importantly, how can I use them? | |
20:00 Tony Morris: the answer to c) is simply: practice and you will start seeing these patterns all over the place -- they are already all throughout your code | |
20:00 Tony Morris: I see these questions often, "I have a List of Wibble and I want a Wibble of List, how do I do this?" | |
20:00 Tony Morris: answer: well if Wibble is a monad (and it probably is), then call sequence1 | |
20:01 Tony Morris: sequence | |
20:01 Tony Morris: so, from here, it is a matter of: concreting in what we have done today | |
20:01 Tony Morris: and then train yourself to spot the patterns in your code already | |
20:02 Tony Morris: right now, it might look a bit gobbley, but actually, a lot of these functions arise all the time in every day programming | |
20:02 Tony Morris: we have covered: | |
20:02 Tony Morris: 1) what is functor? | |
20:02 Tony Morris: 2) what is monad? | |
20:02 Tony Morris: 3) all monads are functors, how? | |
20:02 Tony Morris: 4) what are some monad instances? | |
20:03 Tony Morris: 5) what are some monad libraries? | |
20:03 vj: is filter correct | |
20:03 Tony Morris: from here: | |
20:03 Tony Morris: 1) find more monad instances in every day programming | |
20:03 Tony Morris: 2) find more monad libraries in every programming | |
20:03 vj: oops badwrong | |
20:03 Tony Morris: 3) learn to spot the patterns in every day programming that fit exactly into these instances and libraries | |
20:04 Tony Morris: and that is the whole point of the monad interface | |
20:04 Tony Morris: further, there are other interfaces with different constraints that give rise to other instances and libraries | |
20:04 Tony Morris: monad is just one of those | |
20:04 Tony Morris: questions? | |
20:04 unnamed: Thanks Tony. This helped, especially the combining of monads part. | |
20:05 Tony Morris: great | |
20:05 unnamed: yes thanks | |
20:05 Tony Morris: some mythbusting now: | |
20:05 David T: so the most succinct answer to "why should i care?"... | |
20:05 Tony Morris: 1) monads have nothing to do with side-effects | |
20:05 Marimuthu Madasamy: Thank you so much! | |
20:05 unnamed: off topic what is the equivalent of <|> in Scalaz | |
20:05 Tony Morris: 2) monads have nothing to do with haskell or any specific programming language | |
20:05 vj: oh pretty much useful than other articles on the net | |
20:05 Tony Morris: <|> is in scalaz | |
20:05 David T: is that because it is a pattern that crops up all the time, and gives us a library of functions to use over this pattern? | |
20:05 Tony Morris: David, exactly | |
20:06 Tony Morris: monads are so ubiquitous that even C# has special syntax for them, called LINQ | |
20:07 unnamed: oh yeah. I wrote reader in it after seeing your video | |
20:07 unnamed: https://gist.github.com/vmarquez/4640678 | |
20:07 Tony Morris: yep System.Func can have Select and SelectMany added using extension methods | |
20:07 Tony Morris: Select is what C# calls fmap | |
20:07 Tony Morris: SelectMany is what C# calls bind | |
20:08 Tony Morris: flatMap is what Scala calls bind | |
20:08 vj: i have question filter | |
20:08 Tony Morris: hopefully from here, we can start to see monads popping up all over the place and we know which tool to use! | |
20:08 vj: how do you apply the predicate | |
20:08 Tony Morris: yes filter is tricky | |
20:09 unnamed: yeah i'm lost there too | |
20:09 Tony Morris: you can apply the predicate to h | |
20:09 Tony Morris: you will have a F[Boolean] | |
20:09 Tony Morris: you can use bind to access that Boolean | |
20:11 Tony Morris: just make the types line up | |
20:11 Tony Morris: you won't be definitely right, but you are usually pretty close | |
20:11 aaronlevin: Potentially silly question: if flatMap is bind, and therefore just returns a function F[A] => F[B] how doe ssomething like this actually resolve: | |
20:11 Tony Morris: want to finish off filter? | |
20:12 vj: yes | |
20:12 aaronlevin: List(1,2,3,4).flatMap { x => None } | |
20:12 Tony Morris: flatMap in Scala is usually implemented a bit differently | |
20:12 Tony Morris: flatMap is a method on F[A], taking A => F[B] and returning F[B] | |
20:12 aaronlevin: does it call the resulting function on itself? | |
20:12 Tony Morris: so the arguments are around the other way essentially | |
20:12 Tony Morris: oh wait yeah | |
20:12 aaronlevin: OK, I see. | |
20:12 Tony Morris: that is a scala mistake | |
20:12 Tony Morris: that code above should be a type error | |
20:13 aaronlevin: Really? | |
20:13 Tony Morris: it is annoying how scala does things like this | |
20:13 Tony Morris: Yes. | |
20:13 aaronlevin: Well, you get List[Nothing], so in that sense you're right. | |
20:13 Tony Morris: you are returning Option and not List -> type error | |
20:13 unnamed: it oesn't return List[Any]? | |
20:13 Tony Morris: except scala lets it pass | |
20:13 Tony Morris: the result is a type system escape hatch and also less flexible code | |
20:14 Tony Morris: this is a design flaw in scala and it gets in the way of teaching because of this confusion too | |
20:14 unnamed: will they change it? | |
20:14 Tony Morris: ha no | |
20:14 aaronlevin: yes, i see now, I didn't even consider that. | |
20:14 aaronlevin: I assume their justification is that there is some implicit conversion from Option to List | |
20:15 Tony Morris: you may join the club of those who have lobbied to fix it, but most of us gave up years ago and just live with it | |
20:15 Tony Morris: the real signature takes A => Iterable[B] | |
20:15 unnamed: oh. aarron is right. Cause you can intermix list and option in for right? | |
20:15 Tony Morris: both Option and List satisfy this | |
20:15 aaronlevin: Ah, I see. | |
20:15 unnamed: i noticed that and thought it was weird beofre | |
20:15 Tony Morris: it is apparent "flexibility" that actually causes lack fo flexibility | |
20:16 aaronlevin: I see it as being confusing, but is there a simple example of it creating lack of flexibility? | |
20:16 Tony Morris: well, you can join my club and we don't all it weird, we call it wrong with terrible practical consequences :) | |
20:16 Tony Morris: yes because as we have seen, not all monads are iterable! | |
20:16 unnamed: i mean, this is weird that it compiles | |
20:16 unnamed: List(1,2,3).flatMap(Some(_)) | |
20:16 Tony Morris: in fact, there are many monads that have nothing at all to do with collections | |
20:16 Tony Morris: IntReader is not a collection, you cannot implement Iterable | |
20:17 aaronlevin: Ah, I see, so it may lead someone to try to flatMap a list into a non-iterable Monad and then wonder why they get a compile failure | |
20:17 Tony Morris: the real solution for the problem it attempts to solve is to stack monads | |
20:17 aaronlevin: I have done this before at work I think. | |
20:17 Tony Morris: yes, it handles a few degenerate cases, but completely leaves out a huge number of others | |
20:17 Tony Morris: it would be better to provide the strict flatMap, then stack monads for the cases required | |
20:18 Tony Morris: e.g. if you want to combine the behaviour of List and Option monads, create the appropriate data type (or even better, put it in standard library!) | |
20:18 Tony Morris: case class ListOption[A](x: List[Option[A]]) // is a monad, try it | |
20:19 Tony Morris: in fact F[Option[A]] is a monad for any monad F | |
20:19 unnamed: yeah before I knew what was going on I was perplexed why you could combine list and option but not future and option, etc. | |
20:19 Tony Morris: these kinds of structures are usually called monad transformers | |
20:20 aaronlevin: So it is not true that F[G[A]] is a monad for any two monads F,G? | |
20:20 Tony Morris: Int => F[A] is a monad for any monad F | |
20:20 unnamed: So how do you go from having IntReaderWriter, to just a Reader transofrmer or a writer transformer without actually combining both bind's in one... (so one of them works generically on anohter monad)? | |
20:20 Tony Morris: No. | |
20:20 Tony Morris: and this is a whole new discussion! | |
20:20 aaronlevin: er, I guess there is probably a trivial counterexample where G[A] does not make sense. | |
20:20 Tony Morris: monads do not compose in the general case | |
20:21 Tony Morris: other interfaces do though! | |
20:21 Tony Morris: http://blog.tmorris.net/posts/monads-do-not-compose/ | |
20:21 Tony Morris: functors compose | |
20:21 Tony Morris: try it! | |
20:21 Tony Morris: case class Compose[F[_], G[_], A](x: F[G[A]]) | |
20:21 aaronlevin: Cool. Thanks for the link. | |
20:21 Tony Morris: given functors for F and G, then Compose[F, G, _] is a functor | |
20:22 Tony Morris: applicative functors (yet another related interface) compose in genera | |
20:22 aaronlevin: I guess, structurally, that is where the big differnce between a monad and a functor is? | |
20:22 vj: is my filter correct? | |
20:22 Tony Morris: yes and applicative is in between | |
20:23 Tony Morris: vj: I don't see any calls to bind, so I think it will have a type error | |
20:23 Tony Morris: oh wait yeah there is | |
20:23 Tony Morris: I think the outer most call will be to bind | |
20:23 Tony Morris: bind(...)(p(h)) | |
20:23 vj: okie will try again | |
20:23 Tony Morris: all monads are functors | |
20:24 Tony Morris: all monads are applicative functors and all applicative functors are functors | |
20:24 Tony Morris: you can derive the applicative primitives from monad | |
20:24 Tony Morris: you can derive the functor primitive (fmap) from the applicative primitives | |
20:24 Tony Morris: I can write it if you like | |
20:24 Tony Morris: then you can compose applicatives! | |
20:25 aaronlevin: hah. I can see it mentally. | |
20:25 tpolecat: can you give an example of a data structure for which you can define applicative but not monad? | |
20:26 tpolecat: or does that question not make sense? | |
20:26 Tony Morris: no, it's an excellent question | |
20:26 Tony Morris: case class Accy[A, O](o: O) | |
20:26 Tony Morris: or to be more concrete | |
20:26 Tony Morris: case class IntAccy[O](o: O) | |
20:26 tpolecat: (irc seems to be back) | |
20:27 Tony Morris: this has applicative but not monad | |
20:27 Tony Morris: another interesting question: are there things with bind but not insert? | |
20:27 tpolecat: how does this differ from Id[A]? | |
20:27 tpolecat: they look identical | |
20:27 Tony Morris: oh wait yeah | |
20:27 Tony Morris: you need the forall | |
20:28 Tony Morris: so | |
20:28 Tony Morris: case class Accy[A, O](o: O) | |
20:28 Tony Morris: Accy[A, _] is applicative but not monad | |
20:28 Tony Morris: this data structure is given as an example in Applicative Programming with Effects | |
20:28 tpolecat: ok i'll re-read that. thanks | |
20:28 unnamed: when you say oyu can derrive the applicative primitves from monad, do you mean that's because you have insert and map? | |
20:29 Tony Morris: you have insert and not bind | |
20:29 Tony Morris: brb | |
20:29 unnamed: or if someone else knows what that part meant (aaron?) | |
20:30 aaronlevin: I believe your intuition is correct. Given a Monad F, because it has functions bind and insert means you can define fmap from them. In taht sense, you can derrive a Functor from a Monad. I think its similar with Applicative. | |
20:31 aaronlevin: Monad < Applicative < Functor | |
20:31 aaronlevin: In a set theoretic sense | |
20:31 aaronlevin: (I think) | |
20:31 Tony Morris: I will write Applicative | |
20:31 unnamed: yes. All monads are applicative functors and all applicative functors are functors. | |
20:32 unnamed: However, not all functors are monads etc. | |
20:32 Tony Morris: we are starting to see a pattern here | |
20:33 Tony Morris: all of Functor, Monad and Applicative (ignore insert) have the following: | |
20:33 aaronlevin: I am still trying to think of something with bind but without insert | |
20:33 Tony Morris: 1) a method that takes a function and returns F[A] => F[B] | |
20:33 Tony Morris: 2) that function is a combination of F, A, B in some arrangement | |
20:33 Tony Morris: Functor A => B | |
20:33 Tony Morris: Applicative: F[A => B] | |
20:33 Tony Morris: Monad: A => F[B] | |
20:33 Tony Morris: right? | |
20:34 unnamed: k | |
20:34 Tony Morris: can you think of any other arrangements? | |
20:34 tpolecat: oh very nice. i had never considered that | |
20:34 aaronlevin: F[A] => B | |
20:34 tpolecat: B => A .. is that contra map? | |
20:34 Tony Morris: omg someone said F[A] => B | |
20:34 Ben Hardy: something to decompose? | |
20:35 Tony Morris: guess what we call this! | |
20:35 Tony Morris: go on guess | |
20:35 unnamed: .get | |
20:35 tpolecat: cojoin? | |
20:35 Tony Morris: nope | |
20:35 aaronlevin: lift? | |
20:35 tpolecat: co something | |
20:35 Tony Morris: Functor is to A => B, Applicative is to F[A => B], Monad is to A => F[B], ? is to F[A] => B | |
20:36 aaronlevin: CoMonad? | |
20:36 Tony Morris: comonad! | |
20:36 aaronlevin: I didn't know that existed, so my guess doesn't count. | |
20:36 unnamed: but certainly not every monad can be a comonad | |
20:36 unnamed: right? | |
20:36 Tony Morris: definitely not | |
20:36 Ben Hardy: is that used for getting stuff out of monads? | |
20:36 Tony Morris: comonad also has extract (insert spun around): F[A] => A | |
20:36 Tony Morris: Option has no extract, neither does List | |
20:37 Tony Morris: it can be used for getting stuff out an environment, but not necessarily a monad | |
20:37 aaronlevin: Er, they don't have a pure extract, is what you mean? | |
20:37 Tony Morris: a safe one | |
20:37 Tony Morris: bottoming out doesn't count as existence in my books | |
20:37 aaronlevin: getOrElse ? | |
20:37 unnamed: Future has await... is htat kind of like an extract? (dunno if that's safe, I wouldn't say it is) | |
20:37 Tony Morris: getOrElse has a different type | |
20:38 aaronlevin: right.. | |
20:38 Tony Morris: well, Future is another story | |
20:38 Tony Morris: so, what things have cobind but not extract? | |
20:38 Tony Morris: Future, Option, List, the list goes on | |
20:39 aaronlevin: Forgive me if I'm missing something here, but I do have a method on list that lets me select elements... is this to say that this method does not come from a pure List Monad, but from somewhere else? | |
20:39 Tony Morris: brb | |
20:40 aaronlevin: (... I do have a method on Scala's List ... ) | |
20:40 tpolecat: List[Int]() ... how do you get an int out of that? | |
20:40 unnamed: good point. you can't pass in just a List[A] and get back an A | |
20:40 tpolecat: but Id[A] has a trivial command unless i'm missing something | |
20:41 Tony Morris: does it have the type List[A] => A? | |
20:41 tpolecat: comonad. stupid autocorrect | |
20:41 Tony Morris: Id is both monad and comonad | |
20:41 aaronlevin: Ah, right. I see. | |
20:42 Tony Morris: List[A] => A cannot exist without an escape hatch | |
20:42 unnamed: NonEmptyList could be a comonad? | |
20:42 Tony Morris: so this raises a question, are there things with bind/cobind but not insert/extract? | |
20:42 aaronlevin: Yeah, my gut reaction was to write a stupid version of extract that extracted the list.length element, but that is obviuosly not safe. | |
20:42 Tony Morris: yes NonEmptyList is a comonad | |
20:43 Tony Morris: it is perhaps the most common of all comonads | |
20:43 Tony Morris: list.length will give you Int not A | |
20:43 aaronlevin: def extract(a: List[A]): A = this(a.length) | |
20:43 Tony Morris: there is a lot of discussion on how to best arrange this hierarchy and it is mostly settled | |
20:43 Tony Morris: aaron, that will not type-check | |
20:44 Tony Morris: expected: A, actual: Int | |
20:44 Tony Morris: oh wait I see | |
20:44 Tony Morris: yeah unsafe | |
20:44 aaronlevin: (obviously unsafe) | |
20:44 Tony Morris: how do I *really* think this hierarchy should be arranged? like this https://gist.github.com/3871764 | |
20:44 Tony Morris: oh wait oops | |
20:45 Tony Morris: https://github.com/tonymorris/type-class/tree/master/src/Data | |
20:45 Tony Morris: oh I did it in haskell sorryu | |
20:46 unnamed: well, ScalaZ kinda has one right? | |
20:46 Tony Morris: yes | |
20:46 Tony Morris: it is arranged roughly like this | |
20:51 vj: wow filter | |
20:53 vj: but when its true how we are getting h | |
20:53 Tony Morris: want to know a good exercise that uses filter? | |
20:53 vj: yes | |
20:54 Tony Morris: if I asked you to remove all duplicates from a List, you might use regular filter and a variable holding a Set of currently visited elements, right? | |
20:54 vj: but i thought when its true we need to start build the list | |
20:54 unnamed: yeah.... | |
20:54 Tony Morris: variables, ick! | |
20:54 Tony Morris: how about pass the (immutable) Set around and around instead? | |
20:54 Tony Morris: that can get clumsy, except... | |
20:54 Tony Morris: the state monad! | |
20:54 Tony Morris: case class IntSetState[A](run: Set[Int] => (A, Set[Int])) | |
20:55 Tony Morris: implement Monad for that, then use it in filter to write distinct | |
20:55 Tony Morris: I have a solution somewhere in course code if you like | |
20:56 Tony Morris: https://github.com/tonymorris/course/blob/answers/src/L03/State.scala#L117 | |
20:57 vj: hmmm, thats what your git solution | |
20:57 vj: has it reversed | |
20:57 Tony Morris: reversed? | |
20:57 vj: thats what i was asking | |
20:57 vj: i mean the if condition | |
20:57 Tony Morris: which if condition? | |
20:57 vj: filter | |
20:57 vj: if(b) identityt | |
20:57 Tony Morris: looks good to me | |
20:57 Tony Morris: oh wait no | |
20:57 Tony Morris: woopsie | |
20:58 vj: but the git gist has if(b) h #... | |
20:58 vj: sorry to confuse you | |
20:58 Tony Morris: now if only that was a type error! | |
20:59 aaronlevin: ugh, I got disconnected | |
20:59 Tony Morris: what was the last comment you saw? | |
21:00 vj: i know these require practice, is there a good starting point | |
21:00 aaronlevin: I have full history. So i'm just reading now | |
21:02 Tony Morris: I think we have just taken our first leap off the starting point | |
21:02 Tony Morris: in practice, I find this is best | |
21:02 Tony Morris: push yourself as hard as you can, like we did today -- keep going until you burn | |
21:02 Tony Morris: when you burn, stop and take a break for a couple of days, no writing code, just thinking, in the shower or something | |
21:02 Tony Morris: then repeat it | |
21:03 aaronlevin: quick questoin: what has bind but not insert? | |
21:03 Tony Morris: this is the process for almost everyone, though not everyone starts here -- they usually start doing this on their own | |
21:03 tpolecat: we're discussing that on #scalaz actually | |
21:03 Tony Morris: oh I cannot think of something from the top of my head | |
21:04 vj: cool gotcha | |
21:04 Tony Morris: the dual of any comonad that has the same! | |
21:04 aaronlevin: haha | |
21:04 Tony Morris: I will take 5 and think, brb | |
21:04 unnamed: Promise? | |
21:05 aaronlevin: I can't wrap my head around the idea that a abstract container has no way to put stuff in it. | |
21:05 aaronlevin: *moving to irc)( | |
21:19 Tony Morris: by the way, I wrote some usage examples in Main | |
22:15 Tony Morris: ListZipper comonad, woot! | |
*/ | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment