Added epic tel/gclaramunt thread

This commit is contained in:
Chris Allen 2014-07-28 23:01:52 -05:00
parent 6da4355a45
commit d7f971d26d
2 changed files with 273 additions and 1 deletions

View File

@ -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

View File

@ -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)
```
Thats it people. Thats 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 youre 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, Im
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, heres 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 thats 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? Im intrigued
Since were clarifying what a functor is, I guess is worth noting that
youre 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 youre 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
Its an incredibly overloaded term, tbh. In the context of abstract
algebra youd probably want to think of a (G, L)-algebra as a set
inductively defined by generators G and laws L. For instance, heres a
“free” monoid algebra (note that this isnt 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 Im trying to see how this ties
to the Functor typeclass: G are the instance constructors and the
functor laws make L ? I think Im missing an important piece of the
puzzle here :)
* * * * *
tel 1 day ago | link | reply
Youre not, thats 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 doesnt follow the laws
```haskell
class Functor (FFunctor f) where -- wrong!
fmap = Ffmap
```
but we can implement it properly if were 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 cant use EmbedFunctor
directly without exposing information about whether or not weve ever
fmaped this functor (which shouldnt be possible to access, thats
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. Lets
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 Havent 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 )