Live data from Hacker News

Execution in the Kingdom of Nouns (2006)

steve-yegge.blogspot.de

11–20 of 73 posts

Re: Execution in the Kingdom of Nouns (2006)

#11
post #7

The problem with verbs is that they are black boxes. With objects you can subclass and override methods - do stuff like the Universal Design Pattern - basing something on prototypes that you tweak here and there. Functions you can only apply, objects have parts that have names.

This is why the fundamental operation in the land of the verbs is composition: do this then do that. It turns out that composition is such a useful idea that we want more of it, which is where categories, monads and arrows come in.

The most obvious type of composition for functions is, well, function composition. In math we define the composition of functions f and g as f(g(x)), usually written as f ∘ g. We can write this directly in Haskell pretty trivially:

    f ∘ g = λ x → f (g x)
And, in fact, you will see this operator everywhere in Haskell, except most people are too boring for ∘ and use the ASCII . instead. (Weak.)

Also, a cool aside. I just realized that Haskell syntax is even more regular than I had assumed. In general, in Haskell, you can rewrite expressions like

    f x = λ y → ...
as

    f x y = ...
Turns out this even works for operators! So you could actually write the above composition as:

    (f ∘ g) x = f (g x)
I think that's pretty cool, but maybe I'm just easily impressed.

The idea of a category just takes the ∘ operator and generalizes it to other types, letting you use it for things that aren't normal functions. As I mentioned above, these things could be arrows or functions involving monads, but they can really be anything at all. This is, coincidentally, one of the main reasons we care about category theory: at its very heart, category theory is the study of composition. (Okay, I'm probably really misrepresenting the mathematics here, but that's how it works out for programmers :).)

There are also other things you can do with functions. In particular, you can map functions to other functions. And this is, indeed, what the well-known map function does. Normally, you think of the map function as taking a function and a list and then mapping that function over the list. In Haskell, this has the following type:

    map :: (α → β) → [α] → [β]
However, I posit that map actually does something rather different and more subtle--it takes normal functions and produces list functions. In fact, the type signature is better thought of this way:

    map :: (α → β) → ([α] → [β])
(This is why currying is so great--both interpretations are equally valid!) So, in fact, we can think of the list type as a way of mapping existing types (like a) to new types (like [a]) and mapping existing functions (like (α → β)) to new functions (like ([α] → [β])).

This operation also turns out to be exceptionally useful. So useful, in fact, that it's the basis for one of the most fundamental concepts--the functor. In fact, a functor (in Haskell) is simply any type with a function analogous to the list type's map. For historical reasons, we call this function fmap and it has the following type:

    fmap :: Functor f => (α → β) → (f α → f β)
All this says is that, given a functor type, we can map normal functions to functions over the functor. Another way of thinking about this is that a functor is roughly like a function at the type level.

Of course, we have other ways to transform functions as well; fmap is just the simplest. Similarly, we have other ways to compose functions, function composition is just the simplest.

So the most important idea is that we actually have a fairly wide variety of operations over functions. We can sling them around as easily as any other data type, really.

We move forward by combining functions rather than trying to modify them. Instead of starting with a composite piece and working inwards, we start with the basic building blocks (functions and types) and work outwards, combining them in different ways to get a composite program.

It's a difference in philosophy, and I think a rather important one.

Re: Execution in the Kingdom of Nouns (2006)

#12
post #5

Earlier quoted context omitted.

Well, with CLOS you really define your verb behaviour on tuples of nouns (methods) and the verbs (generic functions) are separate and you can, if you want, get as creative as you want as to how your methods get invoked by your generic functions. [Mind you, it's been a while since I developed in CLOS, so apologies in advance if this is incorrect].

CLOS is really required in about 5% of very specialized tasks, such as simulations.

I'm not sure - "simple" CLOS is really pretty simple and arguably works in a more intuitive way than most OO environments. However, if you do want more sophistication, as with most of Lisp, taking the Red Pill of the MOP can take you as deep as you want to go....

[Damn - I really need to do some more Lisp development]

Re: Execution in the Kingdom of Nouns (2006)

#13
post #11
post #7

The problem with verbs is that they are black boxes. With objects you can subclass and override methods - do stuff like the Universal Design Pattern - basing something on prototypes that you tweak here and there. Functions you can only apply, objects have parts that have names.

This is why the fundamental operation in the land of the verbs is composition: do this then do that. It turns out that composition is such a useful idea that we want more of it, which is where categories, monads and arrows come in. The most obvious type of composition for functions is, well, function composition. In math we define the composition of functions f and g as f(g(x)), usually written as f ∘ g. We can write…

I am enjoying watching this comment grow. I hit refresh every five minutes to get the next installment :)

Re: Execution in the Kingdom of Nouns (2006)

#15
post #7

The problem with verbs is that they are black boxes. With objects you can subclass and override methods - do stuff like the Universal Design Pattern - basing something on prototypes that you tweak here and there. Functions you can only apply, objects have parts that have names.

You can pass functions as arguments to functions, so verbs, too, can have parts.

Re: Execution in the Kingdom of Nouns (2006)

#16
post #7

The problem with verbs is that they are black boxes. With objects you can subclass and override methods - do stuff like the Universal Design Pattern - basing something on prototypes that you tweak here and there. Functions you can only apply, objects have parts that have names.

You can fake objects and subclassing with closures, in addition to making it trivial to implement the "one method interface" (aka "functor").

http://roboprogs.com/devel/2010.06.html (example using a subset of JavaScript, rather than a language likely to be unfamiliar to most)

TODO: edit example someday to get rid of "useless use of local variables" (in place of original formal parameters), fix where I call the outer functions "closures" instead of the inner functions.

Of course, it's easier to work with both real objects AND real functions/closures/lambdas -- I can use a hammer and a screwdriver :-)

Re: Execution in the Kingdom of Nouns (2006)

#17
post #5

Too long. An idea could be stated in a few sentences.) Java: This is an instance of an mammal of an animal kingdom which doesn't include dolphins and whales, which has a..., placed within the instance of a class Plain of polymorphic shape which has some private attributes... ML-family: This is a member of a set of only mammals of animal kingdom, excluding dolphins and whales, of small size, which has a..., located on…

Well, with CLOS you really define your verb behaviour on tuples of nouns (methods) and the verbs (generic functions) are separate and you can, if you want, get as creative as you want as to how your methods get invoked by your generic functions. [Mind you, it's been a while since I developed in CLOS, so apologies in advance if this is incorrect].

>Well, with CLOS you really define your verb behaviour on tuples of nouns (methods) and the verbs (generic functions) are separate

You can do this in any OO language as well: with multi-dispatch patterns. What makes CLOS so powerful is that you can do multi-dispatch without resorting to things like the visitor patters. Simply write what you mean with no boilerplate.

Re: Execution in the Kingdom of Nouns (2006)

#18
This is a real classic. As someone who had only done imperative programming before reading this it really inspired me to give FP a try and led me down the road to trying Scala and then Haskell. However a year into this adventure, I still prefer "nouns". I think the human brain really does work imperatively for most logical problems. I can't deny that for a single problem the functional solution is often more " beautiful" , but the end user can't see the beauty of my voice and I can always think of an efficient imperative solution much faster. I hope one day I'll have a functional epiphany and be able to write Haskell as fast as I can write Java but so far I haven't had such luck.

Re: Execution in the Kingdom of Nouns (2006)

#19
post #11
post #7

The problem with verbs is that they are black boxes. With objects you can subclass and override methods - do stuff like the Universal Design Pattern - basing something on prototypes that you tweak here and there. Functions you can only apply, objects have parts that have names.

This is why the fundamental operation in the land of the verbs is composition: do this then do that. It turns out that composition is such a useful idea that we want more of it, which is where categories, monads and arrows come in. The most obvious type of composition for functions is, well, function composition. In math we define the composition of functions f and g as f(g(x)), usually written as f ∘ g. We can write…

Your explanations of Haskell concepts have been impressing me lately. Do you write elsewhere?
Post reply on HN