Skip to content

Instantly share code, notes, and snippets.

@krishnanraman
Last active October 25, 2016 01:32
Show Gist options
  • Save krishnanraman/4759672 to your computer and use it in GitHub Desktop.
Save krishnanraman/4759672 to your computer and use it in GitHub Desktop.
Tony Morris class
// 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