Skip to content

Instantly share code, notes, and snippets.

Created April 12, 2013 22:39
Show Gist options
  • Save anonymous/5375768 to your computer and use it in GitHub Desktop.
Save anonymous/5375768 to your computer and use it in GitHub Desktop.
00:17:34 <retronym> trepidacious_: comonad/costate isn't really neccessary for lenses. try this presentation: http://www.youtube.com/watch?v=efv0SQNde5Q
00:18:03 ? nomadmonad and milessabin quit
00:18:07 <edwardk> hey that looks familiar
00:18:38 ? jesnor ([email protected]) quit: Ping timeout: 240 seconds
00:20:52 <gseitz> shouldn't costate just be an implementation detail
00:20:53 <gseitz> ?
00:21:04 ? pantsman and j0ran quit
00:21:24 <larsrh> edwardk: are you aware of an introductory paper about comonads?
00:21:43 <edwardk> not really. i gave a talk on them at the first boston haskell i should have some slides handy
00:21:46 ? vsayer ([email protected]) quit: Ping timeout: 244 seconds
00:21:59 <edwardk> http://comonad.com/haskell/Comonads_1.pdf
00:22:03 ? stephenjudkins ([email protected]) quit: Quit: stephenjudkins
00:22:07 <edwardk> it doesn't go very deep though
00:22:17 <larsrh> yeah, I already found that
00:22:24 <edwardk> just motivates the type signature and asks folks to provide derivations themselves for a couple of obvious ones
00:22:31 <mapreduce> This explains 'co' things in general but not particularly comonads: http://blog.sigfpe.com/2007/07/data-and-codata.html
00:22:48 <mapreduce> There appears to be a Comonad.Reader!
00:23:03 <edwardk> thats focused on the notion of codata, you can have a monad made out of a codata and a comonad made out of data
00:23:36 <edwardk> [] is a monad, even if its codata (can be infinitely large and lazy), (,)e is a comonad, even though its data
00:23:58 <edwardk> otoh, data Stream a = a :- Stream a is codata and a comonad
00:24:02 <edwardk> and Maybe is data and a monad
00:24:25 <edwardk> so all four parts of the square are inhabited ;)
00:24:40 <mapreduce> What's (,)e when it's at home?
00:25:17 ? hrehf ([email protected]) quit: Quit: bfg
00:25:20 <mapreduce> I should concentrate on edwardk talking on youtube instead of asking him questions here. :)
00:25:49 › j0ran ([email protected]) joined
00:25:54 <edwardk> at home?
00:26:08 <mapreduce> What's (,)e?
00:26:08 <edwardk> the edwardk on youtube has a pause button. me not so much ;)
00:26:15 <edwardk> lets translate it into scala
00:26:41 <mapreduce> "What's 'foo' when it's at home?" is a colloquialism.
00:27:03 ? j0ran ([email protected]) quit: Client Quit
00:27:20 <edwardk> case class Env[E,A](env: E, extract: A) { def extend[B](f: Env[E,A] => B) = Env(env, f(this)); def map[B](f: A => B) = Env(env,f(extract)) }
00:27:39 <edwardk> (,) e is partial application of the type (e,a) to just the first argument
00:27:45 <edwardk> you can't partially apply types in scala though
00:27:58 <mapreduce> ah, tuple..
00:28:00 <edwardk> (e,a) = (,) e a
00:28:44 <edwardk> in scala you'd need to call it ({ type l[x] = (E,x) })#l
00:28:47 <mapreduce> You have to introduce an extra type to simulate partially applied types afaik.
00:28:51 <edwardk> yes
00:29:00 <edwardk> which is awesome for type inference =P
00:29:47 <edwardk> anyways there .extract takes an Env[E,A] => A and extend takes an Env[E,A] and a function from Env[E,A] => B an gives you an Env[E,B]
00:30:36 <edwardk> other comonad examples are things like the store comonad, which you can make lenses from, case class Store[S,A](f: S => A, s: S) { def extract = f(s); … }
New messages
00:31:13 <edwardk> and if you have a monoid handy you can make a comonad out of M => A
00:31:18 <edwardk> with a monoid on M
00:31:33 <larsrh> my memory betrayed me, I was thinking of http://www.cl.cam.ac.uk/~dao29/drafts/codo-notation-orchard12.pdf, but it's mainly about codo-notation
00:31:35 <trepidacious_> How do you get from wanting to know what a comonad is, to knowing enough that any of that makes sense?
00:31:37 <edwardk> i have a revision control monad/comonad that i've also been working on
00:32:13 › thereisnospoon ([email protected]) joined
00:32:17 <edwardk> you can make codo notation out of the existing monadic sugar, the types just turn out funny
00:32:18 <trepidacious_> It might just be me, but I can't understand any of this without some motivating examples
00:32:20 <edwardk> and its not very useful
00:32:35 <trepidacious_> but thanks everyone for the links, I'll have a look through :)
00:32:39 <edwardk> because all the structure in the comonad is going to be in the position you are pattern matching on, rather than in the right hand side where do sugar gives you space to put stuff
00:33:12 <edwardk> trepidacious_: monads are all about building stuff, if you think about it, a monad takes a structure, expands it, and then smashes the two layers flat, restoring some invariants.
00:33:13 <trepidacious_> and the explanation, it sounds great, I just understand so little to start with, I can't get anything further from any of the explanations
00:33:21 casualjim › casualjim_zzz
00:33:29 <edwardk> the list monad, takes a list, and for every element in the source list, applies a function getting new lists, and then flatMap smashes it all flat
00:33:29 <trepidacious_> trepidaciousOk I kind of get that
00:33:39 <edwardk> so you can only see a little piece when you are building a whole new thing
00:33:53 <trepidacious_> oops don't know why I'm talking to my own nick, sorry carry on :)
00:33:54 <multiHYP> is _ stolen from bash?
New messages
00:34:09 <edwardk> on the other hand a comonad is all about being able to SEE EVERYTHING, when you are making a new value to replace yourself in the next version of the structure.
00:34:10 <multiHYP> I'm going all wacko on yo a$$
00:34:19 <edwardk> lets come up with a compelling example
00:34:23 <edwardk> say you have an array
00:34:32 <edwardk> lets try to make a comonad for image manipulation
00:35:05 <edwardk> case class Pointer[A](arr : Array[A], pos: Int)
00:35:14 <edwardk> where we have an array 'arr' of A's and a position in the array
00:35:18 <trepidacious_> Ah yeah I saw something like that in my wanderings
00:35:24 <multiHYP> seriously can someone help my conscious?
00:35:27 <edwardk> for now its just an Int, but if you want you can make it multidimensional, so you can have X and Y coordinates
00:35:36 <trepidacious_> much easier for me to understand in Scala than the Haskell I found it in earlier
00:35:40 <edwardk> multiHYP: lots of languages use _ for ignoring stuff in patterns
00:35:48 <mapreduce> Wow, scalaquery looks cool.
00:35:50 <multiHYP> please $_
00:35:51 <mapreduce> def * = id ~ name ~ street ~ city ~ state ~ zip
00:36:12 <trepidacious_> So Pointer is to this comonad as Option is to the Option monad?
00:36:14 <edwardk> now, extract for this comonad just gets the element out of the current position.
00:36:16 <multiHYP> i have another monumental question in my pocket too :)
00:36:50 <multiHYP> is AnyValue of type AnyRef?
00:36:50 <edwardk> and extend is interesting. basically what you are going to do is take a function from Pointer[A] => B and use it and the Pointer[A] you have to start with to make a new Pointer[B]
00:37:15 • multiHYP goes into deep mode.
00:37:24 <trepidacious_> edwardk: Sorry one second before we go further
00:37:41 <jamil_1> edwardk: so extends is like bind
00:37:42 <edwardk> that is to say you have a function that expects to use an entire array of input values, and knowledge of the position it is replacing, and you want to apply that function to every position in the source array to make a new array of values
00:37:59 <edwardk> jamil_1: yes, except where bind can only see one tiny piece, extend can 'see' everything, but only builds one tiny piee
00:38:01 <edwardk> er piece
00:38:06 <trepidacious_> edwardk: IIRC, for a monad like List we "go" from A to List[A], or for option A to Option[A]
00:38:14 <edwardk> trepidacious_: yep
00:38:17 <trepidacious_> edwardk: What is the corresponding relationship for this Pointer thing?
00:38:17 casualjim_zzz › casualjim
00:38:27 <edwardk> here we go from extract :: Pointer[A] => A
00:38:39 <trepidacious_> So the important types are A and Pointer[A] ?
00:38:49 <edwardk> yeah
00:39:06 <edwardk> here we only have one constructor
00:39:11 ? bmahe (~bmahe@fsf/member/bmahe) quit: Quit: Leaving
00:39:30 <edwardk> Pointer is a special case of Store, which is built out of the same building blocks as State, just backwards
00:40:09 <trepidacious_> Store is the comonad of State then? The Lens paper calls it CoState?
00:40:18 <edwardk> we need two operations, def extract[A] : Pointer[A] => A and def extend[A,B](p: Pointer[A], f: Pointer[A] => B): Pointer[B]
00:40:30 <trepidacious_> ok
00:40:34 <edwardk> Store is the comonadic version of state, its built by taking the adjunction that gives rise to state and composing it in the opposite order
00:40:49 <edwardk> I _ really_ don't like the name CoState, because it isn't dual to state, its an adjunction composed differently
00:40:57 <larsrh> ! case class Pointer[A](arr : Array[A], pos: Int)
00:40:59 <multibot_> defined class Pointer
00:41:01 <edwardk> it gives no intuition and is an abuse of terminology
00:41:01 <trepidacious_> Take that, dibblego :)
00:41:20 <larsrh> ! def extract[A](ptr: Pointer[A]) = ptr.arr(ptr.pos)
00:41:21 <multibot_> extract: [A](ptr: Pointer[A])A
00:41:29 <edwardk> dibblego gets lots of lumps from me occasionally ;)
00:41:36 <trepidacious_> :)
00:41:48 <pmenon> is there a native scala lib that can convert maps to json strings ?
00:41:53 <edwardk> then extend is tricky, you need to loop over all positions and pass the function each position in turn, while using that to make the new array
00:41:55 <trepidacious_> ok extract makes sense, it is getting the "base" type A back from a Pointer[A]?
00:42:06 <edwardk> yep, it just extracts one value
00:42:34 <edwardk> you can make lots of comonadic 'actions' for Pointer, like one that rotates the current position one left, and then extracts the value
00:42:36 <mapreduce> szeiger: Is scalaquery based on lots of overloads of methods with varying tuple arities?
00:42:46 <mapreduce> szeiger: If so, did you try HList and hit a wall?
00:42:56 <edwardk> where you choose to either clamp or roll around to the other side when you go out of bounds
00:43:17 <trepidacious_> Extend sounds a little like map?
00:43:51 <larsrh> ! def extend[A, B](ptr: Pointer[A], f: Pointer[A] => B): Pointer[B] = Pointer(0 until ptr.array.length map { i => f(Pointer(ptr.arr, i)) }, ptr.pos)
00:43:52 <multibot_> error: value array is not a member of Pointer[A]
00:43:53 <edwardk> so an action we can take in this comonad is to 'blur' it, for instance, we can have an action like def blur(p: Pointer[Double]): Double -- which takes the current position, asks for the values one position above, below, left or right of it, and averages them
00:43:53 <multibot_> def extend[A, B](ptr: Pointer[A], f: Pointer[A] => B): Pointer[B] = Pointer(0 until ptr.array.length map { i => f(Pointer(ptr.arr, i)) }, ptr.pos)
00:43:54 <multibot_> ^
00:43:59 <edwardk> trepidacious_: except it can see more
00:44:06 <edwardk> flatMap is also like map, except it can build more
00:44:14 <larsrh> ! def extend[A, B](ptr: Pointer[A], f: Pointer[A] => B): Pointer[B] = Pointer(0 until ptr.arr.length map { i => f(Pointer(ptr.arr, i)) }, ptr.pos)
00:44:16 <multibot_> error: type mismatch;
00:44:17 <multibot_> found : scala.collection.immutable.IndexedSeq[B]
00:44:18 <multibot_> required: Array[B]
00:44:19 <multibot_> def extend[A, B](ptr: Pointer[A], f: Pointer[A] => B): Pointer[B] = Pointer(0 until ptr.arr.length map { i => f(Pointer(ptr.arr, i)) }, ptr.pos)
00:44:20 <multibot_> ^
00:44:25 ? MKamowski ([email protected]) quit: Ping timeout: 250 seconds
00:44:29 <edwardk> larsrh: yep
00:44:48 › Spion_ (~spion@unaffiliated/spion) joined
00:44:49 <edwardk> ! 0 until 10
00:44:50 <multibot_> scala.collection.immutable.Range = Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
00:44:52 <larsrh> ! def extend[A, B : ClassManifest](ptr: Pointer[A], f: Pointer[A] => B): Pointer[B] = Pointer(0 until ptr.arr.length.map(i => f(Pointer(ptr.arr, i))).toArray, ptr.pos)
00:44:54 <multibot_> error: Unable to unapply type `Int` into a type constructor of kind `M[_]` that is classified by the type class `scalaz.Functor`
00:44:56 <multibot_> 1) Check that the type class is defined by compiling `implicitly[scalaz.Functor[<type constructor>]]`.
00:44:57 <multibot_> 2) Review the implicits in object Unapply, which only cover common type 'shapes'
00:44:57 <multibot_> (implicit not found: scalaz.Unapply[scalaz.Functor, Int])
00:44:59 <multibot_> def extend[A, B : ClassManifest](ptr: Pointer[A], f: Pointer[A] => B): Pointer[B] = Pointer(0 until ptr.arr.length.map(i => f(Pointer(ptr.arr, i))).toArray, ptr.pos)
00:45:14 <edwardk> you are mapping the wrong thing, no?
00:45:21 <edwardk> you need parens around 0 until ptr.arr.length
00:45:26 <edwardk> unless i misparsed
00:45:29 <larsrh> yes
00:45:32 <trepidacious_> So blur is processing one element of the array, but using the context of the entire array, and that is the "type" of function that makes sense for a comonad?
00:45:39 <edwardk> yep
00:45:41 <larsrh> ! def extend[A, B : ClassManifest](ptr: Pointer[A], f: Pointer[A] => B): Pointer[B] = Pointer((0 until ptr.arr.length).map(i => f(Pointer(ptr.arr, i))).toArray, ptr.pos)
00:45:44 <multibot_> extend: [A, B](ptr: Pointer[A], f: Pointer[A] => B)(implicit evidence$1: ClassManifest[B])Pointer[B]
00:45:48 <trepidacious_> That makes a lot more sense
00:46:09 <edwardk> and then when you extend(blur) you'll get a function that takes an entire array with current position to a new array with current position where everything has been blurred
00:46:10 <larsrh> although it's not a real "extend" because we need the `ClassManifest` for array construction :)
00:46:15 <edwardk> notice the shape of the array did not and CANNOT change
New messages
00:46:18 <trepidacious_> was that last definition of extend from larsrh the right one?
New messages since you scrolled up
00:46:21 <edwardk> larsrh: yes
00:46:25 <larsrh> yay
00:46:37 <edwardk> you need to use something other than a scala array
00:46:45 <edwardk> just grab some crap out of the collections library ;)
00:46:57 <larsrh> IndexedSeq, perhaps
00:47:06 <edwardk> you can probably also do it by abusing the ClassManifest for AnyRef or somesuch
00:47:12 › plainflavored joined ? raichoo and nuttycom quit
00:47:28 <edwardk> trepidacious_: looks good to me
00:47:54 <trepidacious_> I need to take a log of this, and then try to write it up, would be very helpful
00:47:55 <edwardk> another example is that you can make a comonad for streams or non-empty lists in several ways, depending on whether or not you want causal or anticausal streams, etc.
00:48:09 <edwardk> another good one is that Promises or Futures can form a comonad in an imperative language
00:48:18 <trepidacious_> I'm having trouble keeping up in real-time, but it all makes a lot of sense I think ;)
00:48:18 <edwardk> where extracting is forcing the future
00:48:25 ? Spion (~spion@unaffiliated/spion) quit: Ping timeout: 260 seconds
00:48:32 <edwardk> and extending builds a more complicated future
00:48:49 <edwardk> this is particularly nice for parallel code
00:49:03 ? kmels ([email protected]) quit: Ping timeout: 245 seconds
00:49:14 <edwardk> you wind up needing a 'strong lax semimonoidal comonad' in order to combine them though
00:49:44 <edwardk> that is to say they need an operation like the ap <*> or |*| or whatever its called in scalaz from Applicative
00:50:01 <edwardk> where that operation is compatible with extract not return
00:50:08 <edwardk> (unit in scalaz)
00:50:27 <edwardk> an example of a comonad like that which is less scary is one i often use in parsers
00:50:40 <edwardk> say you are parsing a function body, and you want to know what variables you have bound in scope
00:50:47 <edwardk> you can pass them around in a comonad
00:51:19 <trepidacious_> Just quickly... in extends, you are creating Pointers that have the index at each element in turn, then applying f to each one
00:52:19 <trepidacious_> But each input Pointer to f just yields the single new element for the resulting Pointer
00:52:31 <jamil_1> edwardk: so....why is it that functors and cofunctors are same but monad and comonad are not (from the posted pdf link)
00:52:34 <edwardk> case class Patterned[A](extract: A, bound: List[Var]) { def ++[B](p: Patterned[B]) : Patterned[(A,B)] = Patterned((extract,p.extract), bound ++ p.bound); def extend[B](…) }
00:52:40 › xlorm ([email protected]) joined
00:52:55 <edwardk> jamil_1: functor = cofunctor just happens when you flip around the arrows you happen to get something with the same shape
00:53:07 <edwardk> there are 'contravariant' functors but there isn't a useful notion of a contravariant monad/comonad
00:53:18 <edwardk> trepidacious_: yep
00:53:53 <edwardk> a fun (infinite) variation is to work out the extend for Store
00:54:12 <edwardk> where instead of an array you are taking a function and making a new function
00:55:47 <trepidacious_> So, now I have something like a clue about one instance of a comonad, I at least have a chance of looking at the more general stuff
00:56:09 <edwardk> the main thing to think about is that the 'shape' of a comonad is invariant. you are just redecorating it
00:56:29 <edwardk> you may have to do some funny things to get all the other comonadic 'views' you need for each position
00:56:40 <trepidacious_> In the same way as for a monad, where the basic pattern is the same?
00:56:45 <edwardk> but overall you're just going to stitch together a bunch of versions of the data you already have
00:56:47 <edwardk> yeah
00:57:26 <edwardk> with a monad you take all your values, get new copies, and stitcht hem together, here we take all the positions, get a modified comonad that 'features' that position correctly and then we use the function to get their replacements
00:59:02 <trepidacious_> So the Pointer comonad features a position via the value of the index?
00:59:18 <trepidacious_> and when you say a modified comonad you are using "comonad" to refer to an instance of Pointer?
00:59:39 <edwardk> yeah, i should say 'comonadic value'
00:59:44 <edwardk> or some such
00:59:56 <edwardk> also notice that comonads work much nicer in scala than monads do
00:59:57 <trepidacious_> I guess in most cases the name of the comonad and the comonadic value are the same, like Option the type and Option the monad?
01:00:36 <edwardk> because you don't have to dispatch everything through implicits you can just bolt extend, extract, map, etc. as members
01:00:36 <edwardk> well, we can have a comonad where you have multiple constructors
01:00:40 ? szeiger ([email protected]) quit: Ping timeout: 260 seconds
01:00:47 <trepidacious_> Yeah it confuses me when reading about monads that scala uses different functions, and doesn't have an actual trait
01:01:18 › dbgster ([email protected]) joined
01:02:05 <edwardk> abstract class Stream[A] { def extract: A, def extend(…); def map(…) } case class Last[A](extract: A) extends Stream[A] { … }; case class Cons[A](extract: A, tail: Stream[A]) extends Stream[A] { … }
01:02:18 <trepidacious_> The Lens paper talks about map and coFlatMap, are they just derived from the extract and extend functions?
01:02:34 <edwardk> coFlatMap = extend,
01:02:50 <edwardk> i just have a different vocabulary than the author there
01:02:59 <edwardk> what Lens paper?
01:03:03 <trepidacious_> Yup I just wanted to check, like with bind/flatMap etc.
01:03:12 <trepidacious_> http://dl.dropbox.com/u/7810909/media/doc/lenses.pdf
01:03:38 <trepidacious_> That's what started me on this, I was following it right up to the comonads appeared ;)
01:04:33 <edwardk> i wrote the scalaz lens implementation which doesn't use store, and the data-lens library in haskell which does, so its funny seeing both in a paper
01:04:52 <trepidacious_> Ah cool
01:05:09 <edwardk> i don't like the partial lenses though
01:05:12 <edwardk> never have
01:05:24 <edwardk> i can't get my head around the bastardized version of the laws they require
01:05:36 <trepidacious_> I've been writing a mutable reactive programming system (Var[T], etc.), and I wanted to see how it would translate into immutable case classes, Lenses etc.
01:05:51 <edwardk> we use lenses for a lot of our code here at clarifi
01:06:05 <edwardk> we have big immutable states we carry around and use lenses to edit them
01:06:19 <edwardk> it was pretty much the first thing i wrote when i got here, which is why scalaz picked up lenses in the first place ;)
01:06:20 <trepidacious_> Yes that was the idea
01:06:28 <trepidacious_> Cool :)
01:06:47 <trepidacious_> My main interest is in GUIs, and binding
01:07:40 <trepidacious_> I was interested in producing a kind of persistent GUI, where images of bits of data are composited and only redrawn when the underlying data changes, if that makes any sense
01:08:12 <trepidacious_> I still haven't seen a nice immutable GUI type thing, so I thought I'd have a go
01:08:41 <edwardk> i need to port my revision control monad to scala, that makes that sort of thing really easy
01:08:57 <trepidacious_> Yeah whenever I think about these things, I am reminded of revision control
01:09:38 <trepidacious_> But the thing I don't understand is that there is so much work done on these things, but I've never run into a library that will take relatively sane looking code and make a nice GUI from it :)
01:09:50 <edwardk> http://research.microsoft.com/pubs/150180/oopsla065-burckhardt.pdf is probably a more accessible presentation than the one i use
01:10:15 <edwardk> in particular the 'incremental' part is what makes what you want go
01:11:36 › stephenjudkins ([email protected]) joined
01:11:56 <trepidacious_> Thanks
01:12:09 <trepidacious_> This is the stuff I want to duplicate (more or less): https://github.com/trepidacious/boxes
01:12:30 <trepidacious_> It works fine, but I keep thinking I should try to get rid of the mutability :)
01:12:39 <mapreduce> edwardk: Not a monad, and not Scala, but: https://github.com/rickyclarkson/inmemgit/blob/master/src/test/java/inmemgit/InMemGitTest.java
01:12:51 <mapreduce> That was fun to write but ultimately useless so far. :)
01:13:05 <edwardk> cute. very different from the code i'm talking about =)
01:13:33 ? AlbireoX`Laptop ([email protected]) quit: Remote host closed the connection
01:14:32 <jamil_1> case class Store[S,A](f: S => A, s: S) { def extends(g: Store[S,A] => B, st: Store[S,A]): Store[S,B] = Store( ss => g(st) , s ) } like this ?
01:14:45 <edwardk> basically the monad lets you specify 'revision controlled variables', where you make up a variable with an initial value and specify a three-way merge strategy for it, and you can then fork and join in the monad, where each time you fork, each fork gets effectively independent copies of the variables, and when you join if both branches edited the value, then the merge strategy is employed using the two new versions and their lowest comm
01:14:45 <edwardk> ancestor
01:15:19 <edwardk> wrong state in the internal one i think
01:15:49 <edwardk> also if you make extend a member of Store[S,A] you don't need to pass in another
01:15:52 <edwardk> just use this
01:16:02 <jamil_1> oh right
01:16:11 <trepidacious_> edwardk: For parallel operations, like an STM?
01:16:52 <edwardk> trepidacious_: except you have deterministic fork and join which ST doesn't give you, and you 'roll forward' merging results on conflict, you don't roll back
01:17:08 <trepidacious_> Sounds good :)
01:17:23 <mapreduce> Ah, now that sounds interesting.
01:17:32 <mapreduce> How do you deal with conflicts you can't resolve automatically?
01:17:38 <edwardk> the part where it becomes relevant to you is you can break the version control metaphor and add a new operation in addition to making variables, reading/writing, forking and joining
New messages
01:18:20 <edwardk> mapreduce: the ability to resolve conflicts is the job of the merge function, if you can't make a merge function, don't use versioned variables for it, and then you can't fork anything where you need to edit that variable in bad ways
01:18:41 <trepidacious_> The writing is presumably not actual mutation, it produces new "revisions"?
01:18:54 <edwardk> making a versioned variable with a merge function is you claiming you have reasoned about the global invariants
01:18:59 <edwardk> yeah
01:19:08 <dibblego> oh hi
01:19:26 <edwardk> i actually improved the known asymptotic bounds on online lowest common ancestor search as a side-effect of my research in this area ;)
01:19:28 <edwardk> heya dibblego
01:20:19 <edwardk> trepidacious_: the metaphor breaking operation you can add is a 'record' function
01:20:25 ? stephenjudkins ([email protected]) quit: Quit: stephenjudkins
01:20:37 <edwardk> which takes Rev[A] => Rev[(A,Rev[A])]
01:20:57 <edwardk> that is to say it computes the answer, and gives you an 'optimized' version of the revision control action for subsequent use
01:21:31 <edwardk> if you view the fork/join graph as a series of operations performed with a set of dependencies for each segment, the idea is to look at what variables have been edited since the first run, to see if you can just recycle the anwer
01:22:01 › stephenjudkins ([email protected]) joined
01:22:09 <trepidacious_> To avoid recalculating values if their dependencies don't change?
01:22:19 <edwardk> that way if you do something like a big parallel sum over a versioned array by forking down to a usable grain size, summing, and then joining the answers, you can recycle the paths where you didn't change the inputs
01:22:25 › SethTisue ([email protected]) joined
01:22:25 <edwardk> yep
01:22:29 <edwardk> now take your screen state
01:22:32 <edwardk> and version it
01:22:33 <trepidacious_> YEs that was the idea with the GUI
01:22:48 <edwardk> =)
01:23:08 <trepidacious_> Yup, so for example editing a "property" of an object would be cheap, because you only redraw the tile that deals with the edited property, etc.
01:23:37 ? bootcode ([email protected]) quit: Read error: Connection reset by peer
01:23:50 <trepidacious_> Combining that with tiles as textures and hardware accelerated compositing seems like it could be good :)
01:24:01 › bootcode joined ? plainflavored quit
01:24:33 <edwardk> =)
01:24:46 <edwardk> my work here is done. let me know when you have a full working implementation i can take indirect credit for
01:25:09 › jihedamine ([email protected]) joined
01:25:12 <trepidacious_> My current system steals the nice idea from another paper with mutable Var stuff, where a "Reaction" is monitored to see what other Vars it reads, and only applies the reaction when one of those changes, so I guess this is a very similar thing, but immutable
01:25:23 <trepidacious_> edwardk: You'd be welcome, thanks for the help :)
01:25:31 <mapreduce> That other paper sounds like FRP.
01:25:47 <trepidacious_> edwardk: My main interest is just in such a thing existing, so that I can use it to make apps ;)
01:26:11 <edwardk> i'll probably port it to scala at some point, but its hard to get enthusaistic about porting haskell code to scala
01:26:48 ? dbgster ([email protected]) quit: Quit: dbgster
01:26:48 <trepidacious_> Because of scala, or because porting code is boring?
01:27:22 <trepidacious_> I'm reluctant to move from scala because I feel like I've finally worked it out a bit, and Haskell seems very intimidating, but equally I've heard a lot of good things about Haskell
01:27:30 ? btby (~user@unaffiliated/btby) quit: Ping timeout: 260 seconds
01:27:50 <mapreduce> Haskell will probably improve your Scala.
01:27:51 <dibblego> I have a "port haskell to scala" battle-suit
01:28:00 <mapreduce> and might make a bunch of things make sense that don't right now
01:28:43 <trepidacious_> But is it ultimately a better language for the type of thing I'm doing? (In as far as I've explained what I'm doing?)
01:29:03 <trepidacious_> Mind you, that is probably a bad question
01:29:25 <dibblego> for learning? yes, far better
01:29:54 <trepidacious_> But not for actually implementing?
01:30:06 <dibblego> why wouldn't it be?
01:30:55 <trepidacious_> I don't know, that was what I was asking, and by qualifying the answer I thought you meant there were non-learning tasks scala might be better for :)
01:31:21 <dibblego> there are some things scala is more suited -- those things have the word "JVM" in the sentence
01:31:21 <trepidacious_> The thing I'm trying to do other than learn, is produce some kind of reactive programming system that can handle conventional looking GUI
01:31:50 <trepidacious_> Right, so basically interoperability with Java stuff is scala's one advantage?
01:31:52 <dibblego> for that, even if I was to end with scala, I'd start with haskell, to get rid of all the mistakes
01:31:57 <dibblego> yes, one
01:32:45 <mapreduce> There are a lot more programmers closer to being able to work with Scala without much retraining than being able to work with Haskell.
01:32:53 <mapreduce> So it's less scary for your corporation too.
01:33:05 › hiratara ([email protected]) joined
01:33:17 <trepidacious_> Hm, still makes my head hurt though :) I think the thing that gets me about Haskell is maybe not even the language at all, just that everything I find to read about it is aimed at people with much more maths/time/brains than me
01:33:17 <dibblego> I don't buy that, but I know many people do
01:33:24 <dibblego> so I can exploit those people, which is an advantage
01:33:39 <trepidacious_> So I find it hard to read anything/learn anything in Haskell
New messages
01:34:02 <dibblego> trepidacious: it's aimed at children -- try it
01:34:07 › looopy ([email protected]) joined
01:34:09 <mapreduce> trepidacious_: Well, maybe they just don't blog about simple stuff, but you'll probably find that once you've got some stuff down it's ok.
01:34:30 ? xiliax ([email protected]) quit: Remote host closed the connection
01:34:31 <dibblego> it will never be simple -- perhaps you're just used to the illusion that programming is not hard
01:34:35 <trepidacious_> dibblego: That means nothing, there are MANY children who are much smarter and more mathematically inclined than me
01:34:46 <dibblego> trepidacious: that was my point; it means nothing
01:35:24 <trepidacious_> dibblego: No that's not what I meant. I mean that the basics for discussion of Haskell are much higher than they are for other languages, which is a bit of a barrier to entry
01:36:06 <trepidacious_> mapreduce: Yup probably, but its like a ladder that starts at about 10 feet up - some people can probably jump up to it, I've tried a few times and failed ;)
01:36:19 <dibblego> but they are not
01:36:29 <dibblego> there is no "higher barrier"
01:36:48 <dibblego> the best bit about that is that if/when you work that out, you get to laugh at yourself, which is fun
01:37:08 <mapreduce> Use it as a calculator for a bit. :)
01:37:12 <mapreduce> @quote posh
01:37:12 <lambdabot> ricky_clarkson says: Sorry, I only use Haskell as a posh calculator.
01:37:16 › AlbireoX`Laptop ([email protected]) joined
01:37:25 <trepidacious_> dibblego: I've talked to you enough times (and it's been very helpful, thank you) to know that what you consider a barrier to entry and what I consider one, are very different things ;) I think you just can't see things from my level ;)
01:37:37 ? AlbireoX`Laptop ([email protected]) quit: Remote host closed the connection
01:37:46 <dibblego> ok, and you are free to keep thinking that, and you are free to keep being wrong and not getting it and that is fine -- I lose nothing
01:37:59 <dibblego> well, I potentially lose the library that edwardk wants
01:38:13 <dibblego> it must be me right?
01:38:47 <edwardk> trepidacious_: mostly because of scala's limitations
01:38:54 <trepidacious_> dibblego: The thing is, since using scala a bit, I feel like some of the stuff that I used to consider very hard to understand now seems simple, and I think there is a LOT more stuff like that I still need to understand that you obviously consider simple too. But just because I find it simple now, doesn't mean I can't remember the pain of trying to work it out ;)
01:39:17 <dibblego> by the way, I find it funny when confused people start talking about "levels"
01:39:20 <dibblego> sorry
01:39:46 <dibblego> trepidacious: that's the thing, *nothing* is simple and the thing for you work out, is that it will *always* be that way
01:39:54 <trepidacious_> dibblego: Level of understanding/knowledge/experience
01:39:59 <dibblego> I do see it from your perspective, you just haven't worked it out yet
01:40:07 <trepidacious_> hm, I'm not convinced ;)
01:40:11 <dibblego> and I will wait patiently for that to change, so I can have that library
01:40:17 <trepidacious_> heh ;)
01:40:40 <trepidacious_> I think I do have a point though, if probably not the one I seem to be jabbering about
01:41:17 ? hiratara ([email protected]) quit: Remote host closed the connection
01:41:17 <trepidacious_> A page on Haskell will talk about monads, categories, monoids, etc. A page about Scala is a bit more likely to just set down to an example of some kind of common task and hwo to do it.
01:41:21 <dibblego> it's an anxiety disorder for which I have no cure
01:41:23 <trepidacious_> I don't think either one is right or wrong
01:41:37 <trepidacious_> but I do know that the scala page can be followed with less terminology, generally
01:41:51 <trepidacious_> the terminology is very useful, but still gives a barrier to entry while I comb wikipedia again
01:41:56 <trepidacious_> that was all I meant
01:41:57 <dibblego> yes, Scala can make concepts harder to understand, unnecessarily
01:42:38 <trepidacious_> maybe ultimately, but I'm not sure everyone can start from the abstract concept without a concrete example
01:42:59 › ivan____ ([email protected]) joined
01:43:14 <dibblego> it doesn't work either way, because it is an anxiety disorder
01:43:31 <trepidacious_> Hm? Not knowing what a monad is, is an anxiety disorder?
01:43:36 <dibblego> nope
01:43:47 <trepidacious_> That actually makes a lot of sense, most people I know are anxious :)
01:43:53 <trepidacious_> I put it down to the economy
01:44:10 <dibblego> one day you will realise "monoid" is actually much easier to understand than some garbled piece of paper with scala all over it
01:44:27 <dibblego> and then you will say, "gee I was being a dick head, maybe I should ease up on the anxiety"
01:44:32 <trepidacious_> heh
01:44:33 <dibblego> and then you'll repeat this over and over
01:44:39 <dibblego> and then the anxiety disorder will disappear
01:44:50 <mapreduce> @type Monoid
01:44:51 <lambdabot> Not in scope: data constructor `Monoid'
01:44:54 <dibblego> and we will sit at the pub and say, "remember when you were scared of the word monad, yeah lol!?!!"
01:45:00 <mapreduce> @type Monad
01:45:01 <lambdabot> Not in scope: data constructor `Monad'
01:45:06 <mapreduce> :t Monad
01:45:07 <lambdabot> Not in scope: data constructor `Monad'
01:45:07 <dibblego> I can do nothing until that day, because I have no cure
01:45:10 <mapreduce> argh
01:45:13 <mapreduce> that used to work
01:45:32 <dibblego> writing garbled scala on a piece of paper and saying, "yeah this is the real shit" is just an illusion -- an appeasement of the disorder that helps nobody
01:45:33 <trepidacious_> The thing is though... if I have looked at a page about Monads several times, read the explanation, diverted into an (infinite?) descent through Wikipedia pages about it, then given up, how does that help me learn?
01:45:49 <dibblego> you're already ill-prepared to learn, with that anxiety
01:45:52 <trepidacious_> But now I can (more or less) read the same pages, and have half a clue what they are talking about
01:46:05 <dibblego> imagine retracing those steps without it
01:46:34 <dibblego> I saw a really good example of this issue recently by the way
01:46:41 <dibblego> http://meta.stackoverflow.com/questions/134333/how-to-avoid-scaring-off-beginners-with-advanced-answers
01:46:49 <trepidacious_> and the intervening stage wasn't just manning up and magically understanding, it was using some monads in scala, and building up some kind of mental framework and familiarity that then gave the abstract explanation somewhere to settle in my confused mind ;)
01:46:55 <dibblego> the "layers of wrong" here are quite startling
01:47:13 <dibblego> why did that take you longer than 5 minutes? what were you doing the other time?
01:48:39 <trepidacious_> Reading the article, encountering a term I didn't know, looking up that term, encountering a term I didn't know, etc.
01:48:49 ? bootcode ([email protected]) quit: Ping timeout: 252 seconds
01:49:07 <trepidacious_> Not having an intrinsic ability to understand the full implications flowing from an abstract concept without having my hand held as some of those implications were spelt out?
01:49:19 › hiratara ([email protected]) joined
01:49:31 <trepidacious_> Just plain not being at a level of understanding where the things that are interesting and comprehensible to Haskell bloggers are the same to me?
01:49:51 <trepidacious_> Like gears in a car... 5th gear is an awesome gear, but not for pulling away
01:50:29 <trepidacious_> An article that reiterated every simple concept in order to get to the more complex concepts and be a complete how to guide... that would be a LONG and boring article for the people who actually wanted to read about the advanced stuff
01:50:53 <mapreduce> You need a directed acyclic graph that gets you from what you know to what you want to know.
01:50:56 <mapreduce> :)
01:51:03 <trepidacious_> But I can only find the complex articles, not the hand holding introduction ones - this isn't so much about Haskell as my ability to find the articles I should be reading, I guess ;)
01:52:05 <dibblego> that has to do with unfamiliarity of concepts, not haskell
01:52:12 <trepidacious_> Absolutely, yes
01:52:14 <dibblego> btw, programming is hard
01:52:18 <ivan____> trepidacious_: in the last 2 weeks ive just been googling a lot for articles, reading htem all even if i dont understand
01:52:34 <trepidacious_> None of this was meant to be against Haskell in any way, just an explanation of why I keep finding it hard to get into
01:52:41 <ivan____> and then im going back over them now and i understand more usually
01:52:52 <trepidacious_> Which as I say could be as much down to my poor googling as anything ;P
01:52:57 <dibblego> some people, when faced with this proposition, completely shit themselves and babble crap forever -- some suspend disbelief which I expect you are doing
01:52:58 ? hiratara ([email protected]) quit: Remote host closed the connection
01:53:43 <trepidacious_> dibblego: Well my current approach is m=pretty much what ivan____ is doing, combined with hacking away at scala because it can do some of this stuff, and I know roughly what the syntax and libraries look like now ;)
New messages
01:54:15 <dibblego> some people complain that "papers use haskell and this is unfamiliar"
01:54:27 <dibblego> when actually, haskell is so easy it is already familiar
01:54:41 <dibblego> but it's just programming concepts are unfamiliar
01:54:58 <trepidacious_> Yup, but the basic primers in those concepts seem hard to find, IMHO
01:55:05 <dibblego> I advise, get used to this -- the next will always be just as unfamiliar
01:55:06 <trepidacious_> at least in haskell, less so in scala
01:55:07 <ivan____> yeah ive started to read more haskell docs now that its sorting itself out in my head
New messages
01:55:41 <dibblego> however, those who complain loudest feel threatened by the prospect that "programming is hard" and "basic programming concepts are unfamiliar to me"
01:55:46 <ivan____> being able to read function sigs in haskell seems to go a long way heh
01:55:46 <apeshimam> trepidacious_: Im nowhere near an expert in many of the concepts you've mentioned but I do find the simplicity with which haskell presents concepts much easier to consume than scala
01:55:50 <trepidacious_> I can now follow the definitions of monads, etc. in Haskell, because the concept of first class functions is a bit more familiar.
01:55:53 <dibblego> just don't be one of those and you'll be fine
01:56:20 <mapreduce> :t fix
01:56:21 <lambdabot> forall a. (a -> a) -> a
01:56:50 <mapreduce> Things like that mess with my head.
01:56:51 <pfurla> dibblego: i admit to these quotes myself despite not feeling threatened
01:56:59 <trepidacious_> It really isn't so much about the language as the available learning materials, for me... I agree that scala as a language seems VERY complicated, although the subset required to do a lot of interesting stuff seems much smaller. Equally the bits of Haskell I've understood seem very elegant
01:57:55 <apeshimam> so beyond blog posts what have you tried? a lot of this is determining what style of learning works for you, IMO
01:58:57 › voidcoder ([email protected]) joined
01:59:08 <trepidacious_> dibblego: I know what you mean - for example it seems one reason that people won't try something new (like scala say), is that they feel stupid when they don't understand something, and that is inevitable when looking at a different programming "model". I'm allowing for that, I felt fairly dumb when learning scala, so I'll allow the same process for Haskell.
01:59:33 ? voidcoder ([email protected]) quit: Read error: Connection reset by peer
01:59:39 <trepidacious_> dibblego: My problem is not so much feeling stupid or threatened in my insular imperative ways, as just not managing to work out what the words mean, but I'll keep giving it a go ;)
02:00:03 › voidcoder ([email protected]) joined
02:00:05 <dibblego> then you will get there, slowly at first
02:00:45 ? ornicar ([email protected]) quit: Ping timeout: 260 seconds
02:01:02 <mapreduce> I felt more stupid when facing Crystal Reports and stored procedures than Haskell or Scala have ever made me feel.
02:01:09 <trepidacious_> dibblego: Yup. Maybe I should put my money where my mouth is, and actually try to document the process, at the very least I could try to put some basic concepts in the order someone might want to approach them. I'm surprised no one else has, I'd love to know how people learn Haskell from scratch :)
02:01:25 <dibblego> try telling someone else what monad means
02:01:39 <qU1j0t3> dibblego | for that, even if I was to end with scala, I'd start
02:01:41 <qU1j0t3> with haskell, to get rid of all the mistakes
02:01:44 <mapreduce> because I didn't know how to take that next step towards understanding more, which always seems to be visible in Haskell or Scala.
02:01:49 ? voidcoder ([email protected]) quit: Read error: Connection reset by peer
02:02:05 <ivan____> trepidacious_: i dont really think you can help people learn it, since it wont make sense to someone that doesnt know - which is the whole problem i think
02:02:26 <trepidacious_> ivan____: Yeah, I know what you mean, although that seems like chicken and egg :)
02:02:46 <ivan____> what it means is there is no silver bullet, you just have to put in the hard work
02:03:01 › rbarraud ([email protected]) joined
02:03:05 <ivan____> i remember doing the same thing when i first started programming
02:03:14 <ivan____> i was always totally confused
02:03:15 <ivan____> lol
02:03:46 <trepidacious_> ivan____: No silver bullet, but... Ok an example - when I was looking at monads, I found a page that spelt out the exact names used for each function in each language (most importantly haskell and scala) and gave some examples. It was harder work finding that than if someone had pointed me at it
02:03:47 <pfurla> mapreduce: ergh, only had bad experiences of crystal :/
02:03:54 <mapreduce> Me too.
02:03:54 <pfurla> s/of/with
02:04:09 <trepidacious_> ivan____: The whole reading/understanding thing can't be done for you, but a nice tour of some pages that make sense and fit together will help a LOT :)
02:04:42 <dibblego> C# has monads built right in to the language, but nobody seems to notice -- possibly because the implementation is quite degenerate
02:04:51 <ivan____> my biggest problem is applying what i learn to my own problems
02:05:04 <mapreduce> People notice C#'s monads.
02:05:12 <ivan____> i can read and even somewhat understand other peoples examples
02:05:13 <dibblego> they didn't when I last checked
02:05:26 <dibblego> I once told #csharp that monads were in their language and they got very upset
02:05:30 <pfurla> actually i don't even think i really used it, the company i worked for only used it to generate pdfs and have easy "print' buttons everything else was text based :/
02:05:46 <trepidacious_> dibblego: I think after people have used those for a while, they might be more likely to understand the general concept though. Then I agree, you probably need to tweak their understanding a bit, but you have somewhere to start ;)
02:06:01 <mapreduce> One of the ##csharp regulars ported a good chunk of Haskell's prelude to C#.
02:06:20 › voidcoder ([email protected]) joined
02:06:22 <ivan____> dibblego: it seems to be that people get upset as soon as they here it because of the brainwashing - same thing when i hear people talk about scala's "academics"
02:06:28 <dibblego> maybe they figured it out by now -- this was years ago
02:06:45 <mapreduce> 3 years ago I joined for the first time.
02:07:08 <edwardk> mapreduce: works well until you start wanting to do something like use a function polymorphic in the choice of monad, etc.
02:07:10 › jcazevedo ([email protected]) joined
02:07:24 <trepidacious_> I was very impressed that there's a nice browser based Haskell REPL thingy and some tutorials now, it's going in the right direction. I was just sad when I ran out of tutorials
02:07:25 <mapreduce> edwardk: LINQ? Yes, the monad is statically decided.
02:07:45 <dibblego> sequenceList, sequenceMaybe, sequenceReader, sequenceState
02:07:59 <edwardk> mapreduce: yeah, i die a little inside every time i have to write the same code to work with the reactive framework and some other linq provider
02:08:05 <mapreduce> Is Scala better that way?
02:08:16 <dibblego> sure, it has TC polymorphism
02:08:30 <dibblego> for-comprehensions are not though
02:08:30 <edwardk> mapreduce: yes, you can write code that is parametric in higher kinded types
02:08:39 <mapreduce> after all, flatMap/foreach/filter/map aren't actually part of a trait.
02:08:53 <mapreduce> or at least you don't need them to be to use for-comprehensions.
02:09:02 <dibblego> wouldn't it be nice?
02:09:03 <edwardk> mapreduce: no, but you can be parametric in some M, and use a scalaz Monad
02:09:19 <dibblego> trait Bind[F[_]] { def map... def flatMap... }
02:09:40 <edwardk> for comprehensions are so awful that i spent a week or so _removing_ monads from a large swath of code at work
02:10:30 <trepidacious_> Well, thanks again for help, 1AM is probably too late to be trying to think straight... I'll let you all know when I get my super-gui library going ;)
02:10:34 <edwardk> dibblego: http://hpaste.org/68398 is the set of trait mixins we use here
02:10:35 <dibblego> edwardk: btw, have you written the partial lens laws out?
02:10:41 <edwardk> dibblego: i did at some point
New messages
02:10:49 <dibblego> yeah me too, and got a bit tangled up
02:10:58 <edwardk> they are (Store s :+: Id) comonad coalgebras
New messages since you scrolled up
02:11:00 <edwardk> easy ;)
02:11:09 <edwardk> this is why i hate partial lenses
=====================================
21:16:20 <Apocalisp> for that you should use the comonad
21:16:40 <atoll> what do you mean ?
21:16:46 <Apocalisp> extend it with a function that takes a tree and turns it into the pair
21:16:51 <atoll> (i mean the comonad is the treeloc no ?)
21:16:58 ? noelw ([email protected]) quit: Quit: noelw
21:17:04 <Apocalisp> no, both Tree and TreeLoc are comonads
21:17:20 <atoll> ?
21:17:31 <Apocalisp> TreeLoc is a zipper on the Tree, but Tree by itself is also a comonad
21:17:37 <atoll> of what ?
21:17:44 <atoll> of A ?
21:17:47 › ornicar joined ? RSchulzM quit
21:18:05 <lizzin> d_m: are you familiar with mongo
21:18:05 <lizzin> ?
21:18:46 › zer ([email protected]) joined
21:18:46 <d_m> lizzin: no, i've never used it.
21:18:51 › _eclark joined ? kjetilv quit
21:18:53 <Apocalisp> atoll: What do you mean of what?
21:19:06 <atoll> well Tree is the comonad of what
21:19:13 <d_m> i've heard a wide variety of opinions on it though. as far as your problem, it almost sounds like your client is connecting to the wrong server or something.
21:19:16 › kjetilv ([email protected]) joined
21:19:22 <Apocalisp> atoll: There exists a Comonad[Tree]
21:19:28 <d_m> or maybe you aren't replicating the data, or aren't saving it properly or something... *shrug*
21:19:35 <Apocalisp> atoll: As well as Comonad[TreeLoc]
21:19:51 <atoll> well Comonad[Tree] is TreeLoc no ?
21:19:58 <Apocalisp> atoll: no
21:20:20 ? arussel ([email protected]) quit: Ping timeout: 248 seconds
21:21:05 <lizzin> hrmm
21:21:49 › noelw ([email protected]) joined
21:22:16 <atoll> but if TreeLoc is the zipper of tree, it's his comonad no ?
21:22:31 ? kushal (~kdas@fedora/kushal) quit: Read error: Operation timed out
21:23:44 <Apocalisp> Do you understand what a comonad is?
21:24:00 <atoll> not totally but i think
21:24:03 ? scorphus (~scorphus@CAcert/User/scorphus) quit: Quit: Leaving
21:24:31 <Apocalisp> Comonad is an interface with two methods.
21:24:54 <atoll> copoint and i forgot the other one
21:25:07 <Apocalisp> extend
21:25:10 <Apocalisp> or cobind
21:25:16 <Apocalisp> I forget which it's called
21:25:27 <FurnaceBoy> wow, if YOU forget what hope is there for we mortals :-<
21:25:43 <Apocalisp> but the type of cobind is (W[A] => B) => W[A] => W[B]
21:25:53 <Apocalisp> FurnaceBoy: The type is what's important :)
21:26:00 <FurnaceBoy> :)
21:26:02 › RSchulzM ([email protected]) joined
21:26:04 <FurnaceBoy> Apocalisp: j/k.
21:26:21 <atoll> i call it reverse flatmap
21:26:34 <Apocalisp> it's the dual of flatMap
21:27:06 <Apocalisp> anyway, you can get a tree with all of the treelocs in it
21:27:20 <Apocalisp> tree.cobind(t => (t.loc, t))
21:27:45 <atoll> i dont understand how it works but thanks
21:28:03 <Apocalisp> It will first construct a Tree of all the subtrees
21:28:18 <Apocalisp> then map the function over that tree
21:28:32 <Apocalisp> each tree will be turned into a pair of: itself and its loc
21:28:42 <atoll> a Tree of all the subtrees ? isn't that the normal tree ?
21:28:47 <Apocalisp> no
21:28:56 <Apocalisp> Tree[Tree[A]]
21:28:59 <atoll> oh
21:29:02 <atoll> ok
21:29:13 <Apocalisp> Where each Tree in the outer tree is the full subtree from that node down
21:30:02 ? noelw and RSchulzM quit
21:30:35 <Apocalisp> it's like tails
21:30:40 <Apocalisp> ! List(1,2,3).tails
21:30:41 <multibot_> Iterator[List[Int]] = non-empty iterator
21:30:42 › futurechimp and dspanks_ joined
21:30:48 <Apocalisp> oh well
21:30:59 <Apocalisp> it's a list of all the sublists
21:31:02 <Apocalisp> well, tails
21:31:48 › kjetilv1 joined ? blooo and headius quit
21:32:36 <atoll> i maybe understand it wrong but will it not create the treeloc of each subtree instead of the treeloc of the node with focus on the subtree ?
21:32:50 › blooo ([email protected]) joined
21:33:14 <Apocalisp> oh yeah, you're right
21:33:18 <Apocalisp> ok, so...
21:33:20 ? kjetilv and dspanks quit
21:33:40 <Apocalisp> tree.loc.cobind(t => (t.toTree, t)).toTree
21:33:44 › blackrain joined ? SHODAN quit Arr`Gone › Arrgh
21:35:34 <atoll> oh nice
21:35:36 › SHODAN, lnostdal_, RSchulzM and blooo_ joined
21:39:15 <Apocalisp> of course, a TreeLoc always lets you get the subtree under focus
21:39:56 <Apocalisp> so tree.loc.copoint.toTree does the same thing, essentially
New messages
21:40:37 <Apocalisp> comonads are pretty awesome
21:40:48 ? blooo and sbenthall quit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment