Live data from Hacker News

Why functional programming?

news.ycombinator.com

31–40 of 60 posts

Re: Why functional programming?

#31
post #19

I think a lot of people gloss over a bit too quickly on the actual implications at a hardware level on what it means to have immutable state. If you have 10mb of numbers that you need to add 1 to, immutable state means you now have 20mb of numbers guaranteed. Allowing for mutable state means you can stick to the 10mb and mutate it. So in general, forced immutable state means that any class of problems which require b…

> If you have 10mb of numbers that you need to add 1 to, immutable state means you now have 20mb of numbers guaranteed.

Immutable state also means that you don't need to add 1 to the numbers you won't use, and that you can discard the old numbers if you only wanted the incremented ones.

Garbage colletors and run-time optimizers are added complexity, and may be too much for an embbebed system (or maybe not, controlers are getting bigger each day). But that's a context dependent conclusion, not a certainty.

Re: Why functional programming?

#32
post #28

Earlier quoted context omitted.

Totally agree on the hardware implementation. Mutable state has two uses. First, when what you are modelling really has state the varies with time (e.g. real world stuff, UI stuff). Second, as a kind of optimization. One good reason for learning FP is that you think more clearly about what mutable state you are using and why. For example, OOP programmers tend to instinctively write obj.setX(x) obj.doG() y = obj.doF()…

State rarely varies with time other than the wall clock, mostly in between time X and Y some events happened. With FP systems you generally have to model these things explicitly and attach a particular time to a particular state which makes the entire system much easier to reason about. Cached state really bothers me because invariably even after caching it, the state can't be reused because of the difficulty of reas…

> I think in reality the appeal of FP is that the people who use it are generally more experienced programmers who tend not to make too much mess in non-FP languages anyway. The benefits are more the peer group than anything else.

Careful, you're arguing here that FP is better because the person using it is a better person. There is nothing wrong with that statement if it is actually an unbiased fact, but simply choosing to use or not use FP would automatically bias you towards declaring that true or false. Avoiding that line of reasoning is a good idea because it's not useful.

Stick to the merits of FP itself.

Re: Why functional programming?

#33
post #9

People mostly benefit from immutable state, which is very useful for avoiding extra bugs. All other "expressiveness" garbage is for those who really dig it.

relevant wikipedia pages:

- http://en.wikipedia.org/wiki/Immutable_object - http://en.wikipedia.org/wiki/Persistent_data_structure

Re: Why functional programming?

#34
post #28

Earlier quoted context omitted.

Totally agree on the hardware implementation. Mutable state has two uses. First, when what you are modelling really has state the varies with time (e.g. real world stuff, UI stuff). Second, as a kind of optimization. One good reason for learning FP is that you think more clearly about what mutable state you are using and why. For example, OOP programmers tend to instinctively write obj.setX(x) obj.doG() y = obj.doF()…

State rarely varies with time other than the wall clock, mostly in between time X and Y some events happened. With FP systems you generally have to model these things explicitly and attach a particular time to a particular state which makes the entire system much easier to reason about. Cached state really bothers me because invariably even after caching it, the state can't be reused because of the difficulty of reas…

> I think in reality the appeal of FP is that the people who use it are generally more experienced programmers

I would wager that FP is used more in universities than in any other setting, and by underclassmen, not just graduate students. So I don't exactly think this is true.

Re: Why functional programming?

#35
> Why functional programming?

At least for the sake of thinking in another paradigm, having another «environment» to think about same issues.

I have scarce experience in functional language but AFAIK there are not only good for in->process->out like it's explained in other post.

Re: Why functional programming?

#36
post #19

I think a lot of people gloss over a bit too quickly on the actual implications at a hardware level on what it means to have immutable state. If you have 10mb of numbers that you need to add 1 to, immutable state means you now have 20mb of numbers guaranteed. Allowing for mutable state means you can stick to the 10mb and mutate it. So in general, forced immutable state means that any class of problems which require b…

Something like "map myints (+ 1)" can be performed in a mutable way, without compromising on functional purity. (So long you're not using the old values afterwards, of course.) Not all compilers perform such optimizations, but there's no fundamental conflict. I believe Haskell's GHC compiler has "fusion" which allows it to wrap chains of maps/filters/folds into a single tight loop. That way you keep functional style,…

You're getting a bit bogged down in details, I meant it more as a general case. There are numerous cases where it is simply more efficient to be operating directly on data - the most used example I can think of are fragment and vertex shaders. It's irrelevant to the issue anyway though: simply having the ability to do something does not make it the best way to do something. You could code in a composable and immutable way using FORTRAN or COBOL if you tried hard enough.

The OP was asking for cases where you'd prefer to be using FP over the type of code he is used to. Manipulating blobs of sensor data are simply unlikely to be a productive use of FP - although it could certainly be done. However, calculating statistics from that data is going to be a place where FP would shine and would be a good choice for it.

Not everything is a nail simply because you can spend hours hitting it with enough transformations to make it look like one.

EDIT: Thinking about it, fragment and vertex shaders actually seem like a very good place to use FP.

Re: Why functional programming?

#37
As someone who only got experience in Haskell I have to ask the same thing. Why should I use X OOP language when I can write almost anything in Haskell with ease? I tried learn programming in C and Python and even the beginner language Scheme, still I did not get programming until I learnt Haskell. Code shouldn't be abstracted as real world objects becuase code is instruction not something concrete you can touch, its information. Abstracting it using a more mathematical approuch very much makes sense and let even a beginner be able to handle quite complex problems.

Re: Why functional programming?

#38
post #32
post #28

Earlier quoted context omitted.

State rarely varies with time other than the wall clock, mostly in between time X and Y some events happened. With FP systems you generally have to model these things explicitly and attach a particular time to a particular state which makes the entire system much easier to reason about. Cached state really bothers me because invariably even after caching it, the state can't be reused because of the difficulty of reas…

> I think in reality the appeal of FP is that the people who use it are generally more experienced programmers who tend not to make too much mess in non-FP languages anyway. The benefits are more the peer group than anything else. Careful, you're arguing here that FP is better because the person using it is a better person. There is nothing wrong with that statement if it is actually an unbiased fact, but simply choo…

Actually I think the poster is right, and I don't think we should avoid all lines of argument that might be subject to personal bias.

The poster was saying that FP has a certain cachet (no pun intended) that is probably due to the quality of the average programmer.

It's a bit like if someone was asked to explain higher salaries in Silicon Valley. Are we allowed to refer to the quality of programmers? Of course there is a risk of personal bias, but how could one have this discussion without referring to this factor?

Re: Why functional programming?

#39
I am not as experienced as you, far from it, but my -very limited - understanding of functional programming is that it's all about limiting side effects, which means limiting the ways you can screw up something. I could try to explain what I think, but John Carmack did it much better than I would ever do in a blog post, that was once submitted on HN: http://www.altdevblogaday.com/2012/04/26/functional-programm...

Re: Why functional programming?

#40
I don't have an answer for you, but for the last year I have been learning Clojure, and I have found it fascinating. I do not think this will satisfy you, but I would like to share some of the things that I find interesting about Clojure.

Lately I've been studying the source code of Aleph, a web server written by Zach Tellman. Zach is a very smart guy, and reading his source code is an education (I've actually found this true of the majority of Clojure projects: the quality of the code is very good, and Clojure is the only language I've worked with so far where I have been able to learn so much reading the source code of the 3rd party libraries that I rely on).

Let's start with an interesting comment about Java, on StackOverflow:

Why doesn't more Java code use PipedInputStream / PipedOutputStream?

http://stackoverflow.com/questions/484119/why-doesnt-more-ja...

In response to that question, matt_b suggests this is part of the reason why people don't use pipedinputstream or pipedoutputstream:

"Typically, data is read from a PipedInputStream object by one thread and data is written to the corresponding PipedOutputStream by some other thread. Attempting to use both objects from a single thread is not recommended, as it may deadlock the thread."

So now, look at how PipedInputStream and PipedOutputStream are used in Aleph:

https://github.com/ztellman/aleph/blob/perf/src/aleph/format...

In particular, look at this function:

(defn channel->input-stream "Consumes messages from a channel that emits bytes, and feeds them into an InputStream."

  ([ch]

     (channel->input-stream ch "utf-8"))

  ([ch charset]

     (let [out (PipedOutputStream.)
           in (PipedInputStream. out 16384)
           bytes (map* #(bytes->byte-array % charset) ch)]

       (future
         (try
           (loop []
             (when-let [msg @(read-channel* bytes :on-drained nil)]
               (.write out ^bytes msg)
               (recur)))
           (finally
             (.close out))))
              
       in)))
I think this is very clean. He uses (future) to put the PipedOutputStream on its own thread, meanwhile he returns a PipedInputStream to whoever is calling this function. This is a good use of PipedInputStream/PipedOutputStream, and he's ensured they run in separate threads, which answers the concern that matt_b raised on StackOverflow.

On a different subject, I have learned a new style of programming by using closures in a functional language. Maybe I am a bit stupid, but it took me a long time before I began to realize how useful closures are. My only other exposure to closures was with Ruby and Javascript, but I never did concurrent programming with Ruby or Javascript, and it seems to me the greatest use of closures is when you are dealing with a lot of threads. When I first started writing Clojure code, I did not use closures at all. I wrote some clumsy code. For instance, I wrote a function that got some data from the database, and I wrote another function that stored that data in a hashmap in memory (using the memory as a cache) and I wrote another function that would check the hashmap for the data, before making the call to the database, and then I wrote another function that ran every 15 minutes and erased items in the hashmap, thus invalidating the cache. But then I realized I could combine several of these operations by creating a closure at the moment that I store data in the hashmap: the closure could call Thread.sleep(900000) and then delete the data from the hashmap. I found it convenient to create the closure while I was storing the data in the hashmap as, at that moment, I have all the information I need, including the key with which that data is being stored. Then I push the closure onto a queue and it gets processed in 15 minutes. This simplifies things quite a bit.

Again, Zach Tellman's code has been educating me about how powerful closures can be in the context of concurrent programming. Look here:

https://github.com/ztellman/aleph/blob/perf/src/aleph/http.c...

And look especially at this function:

(defn wrap-ring-handler "Takes a normal Ring handler, and turns it into a handler that can be consumed by Aleph's start-http-server. If the Ring handler returns an async-promise, this will be handled properly and sent along as a long-poll response whenever it is realized. This should be the outermost middleware around your function. To use an Aleph handler at a particular endpoint within the scope of this middleware, use wrap-aleph-handler."

  [f]

  (fn [ch request]

    (run-pipeline request
      {:error-handler (fn [ex] (error ch ex))}

      ;; call into handler
      (fn [{:keys [body content-type character-encoding] :as request}]
        (if (channel? body) 

          (if (options/channel-ring-requests? request)

            ;; leave channels as is
            (f (assoc request ::channel ch))

            ;; move onto another thread, since there will be blocking reads
            (task "input-stream-reader"
              (f (assoc request
                   ::channel ch
                   :body (formats/channel->input-stream body character-encoding)))))

          (f (assoc request
               ::channel ch
               :body (formats/bytes->input-stream body character-encoding)))))

      ;; send response
      (fn [response]
        (when-not (::ignore response)
          (enqueue ch response))))))
Here you have a function that returns a function that returns another function. The first returned function calls (run-pipeline) and gives (run-pipeline) a closure that will be called later, but with data that we have right now, in this context.

You are asking why functional programming is a big deal. I'm sure different people will have different answers. I think the difficulty in answering is that there is no one thing that by itself makes an answer, rather, it is a whole series of things that combine in powerful ways. For me, the immutable data structures of Clojure are an education. I have learned a lot. I think using closures in the context of concurrent programming could be an absolute nightmare, if it was not for the safety offered by immutable data structures. And yet, I don't think immutable data structures are a big deal by themselves, nor do I think that closures are a big deal by themselves, nor do I think concurrency is a big deal by itself. Only when I look at the combination of these 3 do I find myself enlightened, like I've just discovered a whole new level of programming, a level of power I have never felt in any other language.

A final note: Adam Bard has a blog post "Effortless async by design" in which he says "I dare you to find a thread-safer language. Well, maybe Erlang." And then he also uses some code from Zach Tellman to demonstrate what he means. Bard's post is worth a read:

http://adambard.com/blog/why-clojure-part-2-async-magic/

I could list a lot of things that seem to me very powerful about the coding style I've learned this last year: composability, currying, closures, immutable data structures, thread-safe, etc. But I think descriptions like that tend to be a bunch of meaningless buzz words until you've dived in deep enough to see how they all interact with each other. Because its the interaction of these features that is really powerful, not any of them alone.

Post reply on HN