Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

(serve (fry (add-pan kale (fry (add-pan (dice onions)))))


Better is

    (->> onions
      dice add-pan fry (add-pan kale) fry serve))


Amazing. What's the ->> operator called?


A monad ;-)

No, but seriously, you can think of (->> foo bar baz quux)

As a way of saying:

    Within the context of computing one thing and passing 
    that result to the next thing with a common carrier 
    object of "foo", do bar, then baz, then quux within
    that context, each operating on foo.
In VB you could do:

    with someFile
        readIt()
        processIt()
        writeIt()
See the similarity?

By the way, monads are a way to abstract this even further so that not only can you model the context of "do something to a thing then do the next thing then do the next", but almost every other kind of context you could think of.

EDIT: as has been pointed out, this isn't really a monad, but it's an example of something monad-like that helps me grasp the larger concept better. Also, fixed the syntax.


It's not a monad, it's an ordinary macro. Also, you got the syntax wrong. What you wrote expands to (bar baz quux foo).

To GP: I've heard it called "double arrow" or "post-threading operator".


(->>) is not really a monad, though. It's a concatenation of endomorphisms, which sort of has the smell of a monad, but is simpler.


Not necessarily endomorphisms, though, is it?


True, and then it's a category.


Well, hmm, I don't think that's quite right either. There is a category where the objects are clojure types and the arrows are clojure functions, but I don't see how the threading operator embodies it. There could totally be some perspective I'm missing, though.


No, I think I'm just playing more fast and loose than I should. I don't think it fits into any particular semantic mould because it's really a syntactic thing—it is a list processing function that's applied to source code represented as lists. The basic usage pretty much traces out a path in the Clj category, so perhaps if you built Paths(Clj) then (->>) is a forgetful functor from Paths(Clj) -> Clj. In which case it's almost a monad, since if you play with Paths and (->>) you can turn them into a forgetful/free adjunction pair and make a monad.


Hmm, I think that's right. Heh.


a) yes

b) expanding macros for didactic purposes can also aid understanding

but mostly a)


You joke, but I've often thought how would one write a traditional recipe in a programming language in such a way that it would make sense. Same for "do it yourself" furniture.

Ultimately, I always fall back on programs not having a good concept of "consuming" or otherwise changing a variable. This is clearly doable, and elsewise it was referenced as linear typing (new to me).


C++ with references or C with pointers or Fortran with inout variables would accomplish this, just using normal procedural code:

  contents = open(&ramen);
  add_into( &pot, waterfactory() );
  add_into( &pot, contents );
  add_heat( &pot );
  sleep( RAMENCOOKTIME );
  tasty_ramen = open(&pot);


Right. I did not think I was stating anything grand here. I was simply pointing out that "imperative" mixed with "mutable" state is not something that is hard for users to grasp. Especially when limited in scope to single threads of action. The hard part comes in making sure this "type checks." That is, if you had it dependently typed such that you could not "add_into( &pot, contents );" until after you had "add_into( &pot, waterfactory() );" than you could conceivably catch more bugs.

The trick, to me, is that the "type" of "pot" is not fixed in this. Since I consider the "type" to be dependent on its state. I know this can be done with generic and higher order programming, but usually not with the same reference. That is, each call would create a new reference to pot such that the next one fed off of that. Thing is, that doesn't read well. (I mean, it does for toy examples, but doesn't for long ones.)

Make sense?


Sure.


I feel compelled to give kudos for by far the most readable of the "as program" directions here. Don't get me wrong, I can read most of the other examples, but this is the only one that really reads more true to how you would describe the process to someone and really underscores where I think a lot of the functional advocacy falls flat.


    type Recipe = Food -> Food
    serve . fry . addPan kale . addPan (dice onions) :: Recipe




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: