From d7f971d26dd629661306674f4e575afacf823ef8 Mon Sep 17 00:00:00 2001 From: Chris Allen Date: Mon, 28 Jul 2014 23:01:52 -0500 Subject: [PATCH] Added epic tel/gclaramunt thread --- README.md | 2 +- dialogues.md | 272 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f177785..cd9a5da 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Cabal is equivalent to Ruby's Bundler, Python's pip, Node's NPM, Maven, etc. GHC ## Getting started -### For Ubuntu +### Ubuntu This PPA is excellent and is what I use on all my Linux dev and build machines: http://launchpad.net/~hvr/+archive/ghc diff --git a/dialogues.md b/dialogues.md index 48060c0..e42fed6 100644 --- a/dialogues.md +++ b/dialogues.md @@ -661,3 +661,275 @@ variables 22:46 < bitemyapp> based on the ranks/nesting 22:46 < bitemyapp> / scope'ish ``` + +## Epic Functor, algebra, Coyoneda discussion + +* * * * * + +bitemyapp edited 4 days ago | link | delete | reply + +I realize this is partly because the examples are in Scala, but none +of this gets at what a Functor really is. + +Functor is an algebra. + +Functor is an algebra with one operation, usually called map. + +That one operation has a type something like: + +```haskell +(a -> b) -> f a -> f b +``` + +That one operation should respect identity: + +``` +map id = id +``` + +And that one operation should be associative: + +``` +map (p . q) = (map p) . (map q) +``` + +That’s it people. That’s it. Functor is a very weak structure. Many +things can be functor. Many of those things will not look anything +like a “list”, “collection”, or even a “data structure”. + +Understanding free objects, free versions of these algebraic +structures, can lend a more faithful intuition for what these things +are. + +Glancing at Coyoneda (the free functor) should give one some idea of +why you’re not dealing with something that has anything to do with +lists. + +Want to know more? + +You know the drill: https://github.com/bitemyapp/learnhaskell + +Edit: + +Since I take great satisfaction in excising misunderstandings, I’m +going to include a Functor instance that should help drop the +“collections” oriented view of what they are. + +```haskell +-- (->) or -> is the type constructor for functions +-- a -> a, the identity function's type is a type of +-- -> taking two parameters of the same type (a and a) +-- (->) a a analogous to Either a b +instance Functor ((->) r) where + map = (.) + +-- (.) or . is function composition +-- (.) :: (b -> c) -> (a -> b) -> a -> c +-- more on this Functor instance: +-- http://stackoverflow.com/questions/10294272/confused-about-function-as-instance-of-functor-in-haskell +``` + +Bonus round for upvoting me: + +http://www.haskellforall.com/2012/09/the-functor-design-pattern.html +http://hackage.haskell.org/package/kan-extensions-3.7/docs/Data-Functor-Coyoneda.html +http://oleksandrmanzyuk.wordpress.com/2013/01/18/co-yoneda-lemma/ +http://www.reddit.com/r/haskell/comments/17a33g/free_functors_the_reason_free_and_operational_are/c83p8k2 +https://gist.github.com/thoughtpolice/5843762 + +* * * * * + +tel 4 days ago | link | reply + +``` +Understanding free objects, free versions of these algebraic +structures, can lend a more faithful intuition for what these things +are. +``` + +This is a super great point—it also, meaningfully, applies to other +structures like Monads, Applicatives, or Monoids, Categories, +Arrows. Really quickly, here’s Yoneda and Coyoneda (the “two” free +functors) + +```haskell +newtype Yoneda f a = Yoenda { runYoneda :: forall b . (a -> b) -> f b } +data Coyoneda f b where Coyoneda :: f a -> (a -> b) -> Coyoneda f b +``` + +In each case we see that functor tends to mean having a parametric +structure (the f) and a method of transforming the parameter to +something else (the functions a -> b). When we “collapse” this free +view of a functor we get to decide if, how, when, and why we combine +that structure and its mapping function. For lists we, well, map +it. For something like + +```haskell +data Liar a = Liar -- note that `a` does not appear on the right side +``` + +we just throw the mapping function away. + +(Another key point that’s a bit harder to see is that if you map the +Yoneda/Coyoneda formulation repeatedly it does not store each and +every mapping function but instead composes them all together and +retains only that composition. This ensures that functors cannot “see” +how many times fmap has been called. That would let you violate the +functor laws!) + +* * * * * + +gclaramunt 3 days ago | link | reply + +Do you have any reference of functor being an algebra? I’m intrigued + +Since we’re clarifying what a functor is, I guess is worth noting that +you’re talking about endofunctors in the (idealized) Hask category. In +category theory, a functor is defined by two mappings: one for objects +in the category and one for arrows, that must preserve identity and +composition (the laws you mention). Since the mapping of objects is +already given by the type constructor, here one needs to provide only +the mapping of functions but it kind of irks me when ppl. say a +functor is only defined by “map” :) + +* * * * * + +tel 2 days ago | link | reply + +Functor is definitely an algebra. Its rules mean that it has tight +relation to certain functors in CT. + +* * * * * + +gclaramunt edited 2 days ago | link | reply + +Interesting… any refereces I can read? Or you’re talking about +F-algebras? + +* * * * * + +tel 2 days ago | link | reply + +I mean “algebra” as “set of operations and equalities”. + +* * * * * + +gclaramunt 2 days ago | link | reply + +Ok. To be honest, I need to familiarize myself with the definition of +algebra, is just that I had never heard this before :) + +* * * * * + +tel 1 day ago | link | reply + +It’s an incredibly overloaded term, tbh. In the context of abstract +algebra you’d probably want to think of a (G, L)-algebra as a set +inductively defined by generators G and laws L. For instance, here’s a +“free” monoid algebra (note that this isn’t a free monoid, but a “free +monoid algebra” or a “free algebra of the monoid type” or a “(monoid, +{})-algebra” maybe) + +```haskell +data FMonoid where + Fmempty :: FMonoid + Fmappend :: FMonoid -> FMonoid -> FMonoid + +class Monoid FMonoid where -- this is wrong! doesn't follow laws! + mempty = Fmempty + mappend = Fmappend +``` + +note that it has all the “generators” of the typeclass Monoid but +follows none of the rules (mempty <> mempty != mempty). Typically we +also want to add a set of constants to form the smallest free algebra +over a set + +```haskell +data FMonoid a where + Embed :: a -> FMonoid a + Fmempty :: FMonoid a + Fmappend :: FMonoid a -> FMonoid a -> FMonoid a +``` + +* * * * * + +gclaramunt 1 day ago | link | reply + +Really interesting, thanks a lot! Now I’m trying to see how this ties +to the Functor typeclass: G are the instance constructors and the +functor laws make L ? I think I’m missing an important piece of the +puzzle here :) + +* * * * * + +tel 1 day ago | link | reply + +You’re not, that’s basically it. + +```haskell +data FFunctor f a where + EmbedFunctor :: f a -> FFunctor f a + Ffmap :: (a -> b) -> FFunctor f a -> FFunctor f b +``` + +This lets you build the free (Functor, {})-algebra over some initial +type f. If we translate it naively then it doesn’t follow the laws + +```haskell +class Functor (FFunctor f) where -- wrong! + fmap = Ffmap +``` + +but we can implement it properly if we’re a little more clever + +```haskell +class Functor (FFunctor f) where + fmap f x = case x of + EmbedFunctor fa -> Ffmap f x + Ffmap g fa -> Ffmap (f . g) fa +``` + +We need one more function, though, since we can’t use EmbedFunctor +directly without exposing information about whether or not we’ve ever +fmaped this functor (which shouldn’t be possible to access, that’s +what fmap id = id says) + +```haskell +embed :: f a -> FFunctor f a +embed fa = Ffmap id (EmbedFunctor fa) +``` + +And now, if we think about it, we can see that every value of FFunctor +constructed using embed and fmap is of the form + +```haskell +Ffmap fun (EmbedFunctor fa) +``` + +And so that EmbedFunctor constructor is totally superfluous. Let’s +remove it + +```haskell +data FFunctor f a where + Ffmap :: (a -> b) -> f a -> FFunctor f b + +embed :: f a -> FFunctor f a +embed fa = Ffmap id fa +``` + +And—well—this is just CoYoneda again! + +```haskell +lower :: Functor f => FFunctor f a -> f a +lower (Ffmap f fa) = fmap f fa +``` + +* * * * * + +gclaramunt about 9 hours ago | link | reply + +Nice Haven’t digested it properly but I see the trick is to capture +the functor with a datatype (is the same thing with free monads, +right?) Now is easier to see from where CoYoneda comes, thanks! (you +did show me an important piece of the puzzle :P )