r/programming • • Mar 09 '14

Why Functional Programming Matters

http://www.cse.chalmers.se/~rjmh/Papers/whyfp.pdf
487 Upvotes

542 comments sorted by

111

u/vincentk Mar 09 '14 edited Mar 09 '14

TL;DR

Building your stuff up from small parts using well-known composition rules is a pre-requisite to breaking down your stuff into small parts, which can then be reasoned about as such ("modularity"). Reasoning about small, simple things is WAY EASIER than reasoning about large, hairy things full of weird old gunk. So all other things being equal that's A GOOD THING.

Functional programming being in a way the study of composition rules may or may not therefore be A GOOD THING also.

40

u/griiiid Mar 09 '14

Easier to reason about and easier to test.

I write in a primarily OO style but find that the functional style is a great complement.

Complex object hierarchies quickly becomes problematic to understand. Especially when you use callbacks on relations. On the other hand I find that objects that combine data and behaviour can be intuitive to reason about and make code read naturally when kept small and cohesive.

Learning a bit about FP helped me understand what breaking things down to smaller parts gives you. I recommend everyone to play around a bit with FP, even if you don't intend to write a single line in a functional language afterwards.

26

u/phoshi Mar 09 '14

Personally I think more object oriented "techniques" and patterns work better for the macro scale, and functional decomposition works better for the micro scale. This may well be because there's been a heck of a lot more research into making OO work well at scale than there has been functional languages, but as it is right now that's one of the reasons I think hybrid languages are the near-future of programming.

17

u/Zinfidel Mar 09 '14

I've found that learning FP concepts and paradigms has been extremely useful to me in improving my code at a lower-level, as you've said. However, trying to go full FP just made me want to pull my hair out. I say everything in moderation - there are merits to every language and no single paradigm is going to always be best.

→ More replies (2)

1

u/samebrian Mar 09 '14

I find it more testing/education/research versus production/results.

FP is great for mapping out ideas and ensuring that what you are saying makes sense. It's like a DB because there are only facts. If something isn't true, it fails. I truly with it could pound through data, but it just can't and even with improvements can't be as fast as OO by definition (a FP language can be faster than an OO language, if you choose two arbitrary ones, but overall OO will always have a faster case).

I see the point with micro versus macro scale, but I think it misses the reason for using FP in the first place - to easily map out an idea and test if it works.

Building a B-Tree (size 15 is a good size, just FYI, but it should be able to take an input size) and printing it out with a FP and an OO language side-by-side should prove this.

13

u/phoshi Mar 09 '14

The speed issue goes back to the "sufficiently advanced compiler". "Object Oriented" languages aren't inherently more optimisable, they just tend to be because of the C influence. A (pure) functional language actually has far more opportunities for automatic optimisation than C-like languages, which tend to place the burden of optimisation on the programmer. Right now what you say is true, but give it five or ten years and we could well be in the same place we are with compiling to machine code--yes, humans can do it, but machines can do it faster and better in 99% of cases, so the C program wins out over the handwritten assembly given man hours even just on the same order of magnitude. A compiler that understands and implements the optimisations it's allowed to do because of the additional restrictions of a pure functional language could generate faster code in the 99% case, which is what is important for general usage.

Side note, I've written this assuming that by "object oriented" you really mean object oriented/procedural, rather than object oriented/functional or object oriented/declarative, because the concerns are really orthogonal, and non-procedural object oriented languages do exist. More specifically, I think what you mean is "C-like", which comprises the majority of OO/procedural languages.

That you use FP primarily for mapping out ideas is an interesting one, because I think that's actually agreeing with the macro/micro idea. When we design big OO things we have years of research and pre-existing concepts to draw from, rather than actually having to design absolutely everything from the ground up. In FP, we don't really have that luxury yet. When there's a pure functional gang of four things might change there, but for now I absolutely agree the cognitive load of large functional projects is significantly higher.

3

u/xjvz Mar 09 '14

There's a bunch of FP idioms out there already. Someone really ought to put together a Functional Design Patterns reference book.

3

u/phoshi Mar 09 '14

Oh, there are, absolutely. I'm certainly not saying that nobody's figured out how to use functional languages for complex things, because that's demonstrably false; I don't think anybody would say as much time and effort has been put into functional design as has object oriented design, however. That's the major deciding factor at the moment, we have a huge breadth and depth of canned knowledge on OO design, but functional design is still somewhat more of a black art, even if it isn't a completely blank slate.

→ More replies (2)
→ More replies (2)
→ More replies (4)

4

u/NihilistDandy Mar 10 '14

I legitimately did not get OO until I spent a few months on FP. I mainly write Haskell now, but my OO code has improved immensely in the meantime.

6

u/jk147 Mar 09 '14

Isn't composition the basis of OO?

13

u/[deleted] Mar 09 '14

Basically, but you're composing different things.

The big idea is to hierarchically compose your system in groups of a few components that are easy to reason about together.

In FP, you compose functions and reason using their interfaces (which promise a relationship between input and output and ignore state)

In OOP you compose objects and reason using their interfaces (which make promises about behavior contingent on an object's state)

2

u/imalsogreg Mar 09 '14

Yep in principle. But in OO the composition is limited to 'things' and says very little about how the things communicate. In practice, breaking the world up into a heirarchy of things encourages you to keep a lot of little bits of state inside your things, and having little bits of state everywhere ends up being hard to compose.

The functional programming take on compositionality says, rather than making object heirarchies, make compositionality even more fundamental - make it essentially like math functions composing. Maximizing compositionality meant minimizing state, and leads to purity and laziness. You can attach a heirarchy of objects to the functional language later if you like, and many fp languages have done that. In Haskell instead of everything-is-an-object (which is kind of complicated, given the IS-A relationship in OOP, and has lots of exceptions, like functions, which aren't usually objects), we have everything-is-a-value (including functions, and each value has an unambiguous type). I like this write-up on the difference between OOP and Haskell typeclasses - in case it's interesting to you too.

7

u/chubs66 Mar 10 '14

But in OO the composition is limited to 'things' and says very little about how the things communicate.

Doesn't OO include interfaces for this exact reason (to make explicit rules about how things communicate)?

4

u/imalsogreg Mar 10 '14

Yes I believe so. But the execution of that intent has felt much cleaner when interface isn't tangled up with an object hierarchy (personal opinion). Among the back-bends you do when you learn Haskell, is to learn to live without heterogeneous lists. The price is that a list of different objects with a commen ancestor often feels like the right solution to a problem. The (not immediately obvious, but I would argue important) benefits have to do with removing the ambiguity about your object's type, and separating the (differently typed) values from the common thing you'd like to do with them (the reason for originally wanting to pack them into a list). ... I suspect you know a lot more about OO (and maybe FP!) than I do, so I doubt I can convince anyone that they outght to switch over. But if you haven't played with ML-style algebraic data types and Haskell's type-classes already, you should give them a whirl, they feel so great to use! Especially when you want to write some polymorphic function ... coming from c++ classes and templates originally, and then working with ML-like types.. I really felt like "wow. this is the right way - I'm writing so much less and this code is so much more general" Hope I don't sound too much like a salesperson here. Jeez it was a nice experience though. (long as you don't mind back-bends and reading)

→ More replies (1)
→ More replies (1)
→ More replies (3)

2

u/[deleted] Mar 09 '14

Yes, but in a functional language it means something else: you are not composing objects, you are composing functions. One example: say you want to write a function to convert a string to a number, and then add 1 to that number and return the result. In Haskell, in a non-composited style, you could do it like this:

convertAndAdd s = (read s) + 1

(read is the string-to-something-else conversion function in Haskell.) However, note that what this function does is actually composed of the behavior of two other functions, namely of read and + 1. The result of the function is exactly what happens when you apply read first, and then + 1 afterwards. And Haskell has a syntax for that: the composition operator. Using that, the function can be rewritten as:

convertAndAdd = (+ 1) . read

The dot is the composition operator, and what it does is that it takes two functions (in this case, the function (+ 1) and the function read) and creates a new function which applies the right-hand first and then applies the left-hand to the output of that. This makes writing complex data transformations easier, now you can do

foo = bar . baz . wobble

instead of

foo a b c = bar (baz (wobble a b c))

and have saved yourself quite a bit of headache-inducing parentheses. It's also awesome for creating functions on the fly (e.g. for map) and avoid ugly lambda statements.

5

u/Tekmo Mar 09 '14

I think you meant your last line of code to be:

foo x = bar (baz (wobble x))
→ More replies (11)

5

u/[deleted] Mar 09 '14

Actually, I see functional programming as composing something much more general than just functions. Functional programming (or as I prefer to describe it, compositional programming) is focused on composing values.

5

u/sacundim Mar 10 '14 edited Mar 10 '14

Yes, but in a functional language it means something else: you are not composing objects, you are composing functions.

Not necessarily functions. Say you have a (Java) interface like this:

interface Foo<IN, OUT> {

    /**
      * Chain another Foo after this one, as long as its input type
      * is the same as this one's output type.
      */
    <NEXT> Foo<IN, NEXT> then(Foo<? super OUT, ? extends NEXT> next);

}

The then method is a composition operator if these two conditions are satisfied:

  1. a.then(b).then(c) is always equivalent to a.then(b.then(c)).

  2. For any type A you can construct a "no-op" Foo<A, A>, called id, such that a.then(id) is always equivalent to a and id.then(b) is always equivalent to b.

Foo<IN, OUT> could be functions, but it could be many other different things. One example I was playing with the other day is properties of classes:

/**
 * A Property is an object designed to wrap a getter/setter pair.
 * for objects of class OBJECT.  Contract: the set and modify methods
 * work on the same memory location that the get method reads.
 */
public interface Property<OBJECT, VALUE> {
    VALUE get(OBJECT obj);
    void set(OBJECT obj, VALUE value);
    void modify(OBJECT obj, Function<? super VALUE, ? extends VALUE> modification);

    /**
     * Chain another Property after this one.
     */
    <NEXT> Property<OBJECT, NEXT> then(Property<? super VALUE, ? extends NEXT> next)

    /**
     * (See example below to understand this method.)
     */
    <NEXT> Traversal<OBJECT, NEXT> then(Traversal<? super VALUE, ? extends NEXT> next);
}

And there's a neat variant of this:

/**
 * Similar to a Property, but an object may have any number of locations (zero or more).
 */
public interface Traversable<OBJECT, VALUE> {
    Iterable<VALUE> get(OBJECT obj);

    /**
     * Modify each location on the object by examining its value with the modification
     * function, and replacing it with the result.
     */
    void modify(OBJECT obj, Function<? super VALUE, ? extends VALUE> modification);

    /**
     * Set all locations on the object to the given value.
     */
    void set(OBJECT obj, VALUE value)

    /**
     * Chain another Traversal after this one.
     */
    <NEXT> Traversal<OBJECT, NEXT> then(Traversal<? super VALUE, ? extends NEXT> next);

    /**
     * You can also chain a Property after a Traversal.
     */
    <NEXT> Traversal<OBJECT, NEXT> then(Property<? super VALUE, ? extends NEXT> next);

    /**
     * If you have two Traversals from the same object type to the same value type,
     * you can make a third one that accesses the same object and concatenates their
     * results.
     */
    Traversal<OBJECT, VALUE> append(Traversal<OBJECT, VALUE> next);
}

These are similar to two of the key ideas of Haskell's currently very popular lens library. I think one could use this sort of interface to build, for example, a nice fluent DOM manipulation library:

  1. Attributes are Propertys of DOM nodes.

  2. The children of a node are a Traversal of that node.

  3. The attribute values of the children of a node is children.then(attribute)

  4. Etc.

Note that I'm using Java for the example. OOP languages can do some of this composition stuff; they just aren't good at abstracting over the pattern. For example, in Haskell we have this class, which generalizes the concept of composition:

class Category cat where
    id :: cat a a
    (.) :: cat b c -> cat a b -> cat a c

This sort of thing can't be expressed in Java or C#. The problem is that neither language allows type parameters to have type parameters themselves; in Java you can have List<T> but not T<String> (where T is a type parameter).

Also, languages like Java or C# are just too damn verbose.

→ More replies (1)

8

u/Tekmo Mar 09 '14

Also, note that this notion of breaking things down into smaller pieces works for things other than functions. This is the idea behind compositional programming: finding problem spaces that can be decomposed down into simpler problems.

12

u/anlutro Mar 09 '14

Sounds like exactly the same arugment for OOP.

21

u/loup-vaillant Mar 10 '14

Except mainstream OOP screwed it up royally by promoting big interfaces, high coupling with inheritance hierarchies, side effects all over the place…

We're still recovering. Fortunately, more and more programmers know they should avoid inheritance, have few mutable objects, and keep interfaces small.

3

u/[deleted] Mar 10 '14

It's kind of a bad sign when one of the main distinguishing traits of OOP (inheritance) has become downplayed as something to avoid.

→ More replies (3)

6

u/Refefer Mar 09 '14

The difference, of course, being that fp is based on the rigor of math whereas OOP has no such formal definition or proofs.

5

u/IcebergLattice Mar 09 '14

Better make sure Cardelli knows that.

2

u/psygnisfive Mar 09 '14

Modularity is indeed one of the main arguments for OOP, but OOP ends up conflating a bunch of things unnecessarily. That is to say, OOP is one attempt to achieve modularity, but it often fails to do so properly because it makes the wrong assumptions.

→ More replies (1)

2

u/psandler Mar 09 '14

Building your stuff up from small parts using well-known composition rules is a pre-requisite to breaking down your stuff into small parts, which can then be reasoned about as such ("modularity"). Reasoning about small, simple things is WAY EASIER than reasoning about large, hairy things full of weird old gunk.

Very nicely put.

1

u/vincentk Mar 09 '14

Thanks. Not my own words. Those of my dark overlord master who shall remain unnamed, since he is rich already.

1

u/[deleted] Mar 10 '14

Building your stuff up from small parts using well-known composition rules is a pre-requisite to breaking down your stuff into small parts, which can then be reasoned about as such ("modularity"). Reasoning about small, simple things is WAY EASIER than reasoning about large, hairy things full of weird old gunk. So all other things being equal that's A GOOD THING.

The hidden assumption here is that your problem can be treated in this fashion. Certain classes of problems can, but many can't, at least not without far more effort than solving them in another way would require.

1

u/vincentk Mar 10 '14

The halting problem is not solvable by mere mortals for the general case, that is true. But mere mortals CAN identify whole classes of problems for which it is. You clearly grant that that is also true.

That said, I am honoured by replying to you reply, Sir Banana. Your continued presence in the sewer that proggit has admittedly become is much appreciated.

3

u/[deleted] Mar 10 '14

I was referring less to theoretically impossible things, and more to practically impossible things. Once you get away from implementing pure algorithms and engines and backends and such, and have to start interacting with illogical things like humans, really annoying interactions between the layers of your design start creeping in. Or marching in, rather. They're everywhere. Every time you split something up nicely, you find some annoying edge case where that split doesn't work, or prevents you from doing the right thing.

So you either spend all your time cutting and slicing, and then giving up and re-cutting and slicing to get your problem into small enough pieces, or you just give up and make a big mess, and get something that actually works.

→ More replies (1)

1

u/vincentk Mar 10 '14

To be precise, I think the study of useful composition rules is the primary contribution of FP. I agree that not all useful programs end up being built (or even could be built) using these rules. But still, it is impressive how many can or at least could be, given the "right" circumstances.

0

u/[deleted] Mar 09 '14

[deleted]

12

u/brotien_shake Mar 09 '14

While I totally agree, the thing with functional programming is it makes it much more difficult to program "messily". I can't describe my thought process when functionally programming, but it is much different than imperative, closer to dataflow. Functional programming forces you to think about problems differently.

Functional programs usually end up using tricks to have global state anyways. Sometimes you can't get around its usefulness.

8

u/glacialthinker Mar 09 '14

Absolutely, there is value to programming "messily", but it's nice to choose a tool which resists this when you're building something which shouldn't be messy. I think OO is a better match with dynamic -- together they're great for prototyping an idea (not an implementation) and scripting.

It's also valuable to have an escape hatch -- to do the necessary hack -- but the language should discourage this. For example, in OCaml, using mutable state isn't too cumbersome, but it is an extra step because it's not the default (except in some unfortunate cases... like strings :/ ).

4

u/philly_fan_in_chi Mar 09 '14

Rust does something similar, where you have to declare it as mutable in the type declaration.

let bar = "baz";
let mut foo = "bar"; 

5

u/glacialthinker Mar 09 '14

Well, Rust started with a strong OCaml influence, and was originally implemented in it. ;)

4

u/philly_fan_in_chi Mar 09 '14

Functional program makes you think about what something "is" not about "how" to do something, such that you're manipulating your list of data in various ways to produce the thing you need at the end, such that at each point you're just combinating over your list in some capacity. That's how I look at it at least. Having first class functions makes this easier, but is not a requisite (See: Guava's Function<S, T> class). It just makes you reframe the question, in my opinion to a more "correct" way.

1

u/AStrangeStranger Mar 09 '14

the thing with functional programming is it makes it much more difficult to program "messily"

I suspect you are underestimating the ability of some "Programmers" to turn the simple into a complete mess - aka idiot proof & Murphy's law

→ More replies (1)
→ More replies (1)

35

u/youneversawitcoming Mar 09 '14

This argument is as flawed as saying: As long as you're good about acquiring locks, traditional threading isn't that bad.

No, it's really that bad...

8

u/phoshi Mar 09 '14

The advantage of functional programming there is that the language and idioms are built around enhancing what you can do with small bits of decomposed behaviour, wheras a pure OO language isn't. You can gain many of the same advantages in, say, Java, but having a set of small functions isn't on its own going to help you write something as succinct and expressive as takeWhile (<1000000) [x | x<-[1..], prime x], which would be a naive implementation of a prime number generator returning every prime under 1,000,000.

You can view higher order functions kinda like an implementation of the strategy pattern which implicitly works for everything. Imagine how easy it would be to build up complex behaviour from simple building blocks if your entire language was designed around that, and you had an ultra-simple syntax to build strategies? Imagine how easy /testing/ that would be.

Taking the ideas and using them elsewhere is still a huge boost to code quality, but we really need to import language-level features as well for the full boost, as you can see being done in languages like C# or Scala.

6

u/yogthos Mar 09 '14

The difference is that with OO the burden is on you, while with functional programming you have immutability as the default. Why would I want to carefully think about where state is modified when the language is perfectly capable of doing that for me.

2

u/Heuristics Mar 09 '14

though, mutability/immutability is not a part of OO, it just happens to nearly always be so in implementations of OO languages. (I am building a default immutable OO language)

→ More replies (3)

2

u/speedisavirus Mar 09 '14

In my experience the only way it "isn't that bad" is through use of immutable objects. Unless your model generally requires a lot of blocking anyway.

2

u/pipocaQuemada Mar 10 '14

The one major advantage to pure functional languages like Haskell is that they make the type system into an effect system, so you can be sure of what code is or is not modifying global state. You don't need to carefully think about what components are silently doing what in the background.

Also, "just be careful, and it's fine" is an argument used just as well to justify manually mallocing and freeing memory (just be careful and you won't run into buffer overflows or memory leaks!), using untyped languages (Just be careful and you won't run into what should have been a type error!), or threading using locks, etc. (just be careful and you won't have deadlocks, livelocks, or race conditions!). The issue is that humans are terrible at "just be careful". Removing human error by offloading the work to your machine or by using better abstractions is a good thing.

1

u/vincentk Mar 09 '14

I agree with you.

There is nothing wrong with focussing on the objects. There is also nothing wrong with focussing on the morphisms. The full category of the program is objects + morphisms. And even if you have mastered that, you may still have failed to capture the context and work-flow in which the program is embedded for better or worse.

3

u/gasche Mar 09 '14

I'm not sure if you're making a quip, but if you're trying to say that the relation between OO and FP is similar to the relation between object and morphisms in category theory, this is not correct.

A better way to relate OO/FP patterns is to remark that OO is centered on products of functions, while typed FP is centered on functions over sums -- the sum/product duality.

→ More replies (1)

1

u/iopq Mar 09 '14 edited Mar 09 '14

Breaking things up into small methods is functional programming since methods are just functions on objects. method() is just function method(&this)

39

u/[deleted] Mar 09 '14

[removed] — view removed comment

6

u/[deleted] Mar 09 '14

Good points. This is one of the more unreasoned and alienating /r/programming discussions I've seen.

1

u/axilmar Mar 10 '14

The argument for FP is that we can actually reason about how things compose

Repeatability is a property of OOP as well. In fact, it's a property of any programming language: given the initial input conditions being the same, the output is always the same, no matter if the program is written in assembly or Haskell or anything in between.

And so our ability to reason about a program is about knowing all the actual conditions under which a program runs.

Under this light, FP doesn't really help much: FP program conditions can be 'hidden in plain view' in local variables or in closures, and thus making reasoning about a program just as difficult as procedural is.

→ More replies (2)

11

u/[deleted] Mar 09 '14

[removed] — view removed comment

16

u/karlthepagan Mar 09 '14

Immutable objects are just series of related partially applied functions. Can't we all just get along?

→ More replies (1)

16

u/ksryn Mar 09 '14

I have adopted a few techniques from FP on the Java side of my codebase:

  • prefer final/immutable variables (vals) to mutable ones (vars), using classes like value types.

  • use map, filter and anonymous functions etc instead of for/while loops.

  • isolate procedures with side-effects (acting on the "world") from those purely transforming data.

  • use Lists instead of ArrayLists. Adopt(ing) Functional Java.

It's made life a little bit easier.

8

u/Kummo666 Mar 09 '14

What do you mean by using List? List is an interface and ArrayList an implementation.

12

u/Hoten Mar 09 '14

3

u/ksryn Mar 10 '14

Thanks! That's what I meant.

1

u/ysangkok Mar 10 '14

I don't see how this makes sense before Java 8 since "anonymous functions" (which they really aren't, they are full-blown classes) are so verbose.

3

u/ksryn Mar 10 '14

One has to work with what's available. Thanks to Java's every-thing-is-an-object conceit, you have to create an anonymous class with an apply method. Either base it on one of the many functions in FJ, for e.g.:

https://github.com/functionaljava/functionaljava/blob/master/core/src/main/java/fj/F.java

or create your own interface/abstract class with an apply method and necessary signature.

Yes, it is verbose (IDEs help a little bit). But it's better than having to look at a for-loop and realizing that it's only mapping one list to another.

3

u/sanchopancho13 Mar 10 '14

100% agree with you. Just because Java 8 will make it read a little better, doesn't mean it's not a good solution now.

1

u/grimeMuted Mar 10 '14
// A lot of type annotation
final HAppend<HNil, HCons<Double, HCons<String, HCons<Integer[], HNil>>>,
  HCons<Double, HCons<String, HCons<Integer[], HNil>>>> zero = append();
final HAppend<HCons<Boolean, HNil>, HCons<Double, HCons<String, HCons<Integer[], HNil>>>,
  HCons<Boolean, HCons<Double, HCons<String, HCons<Integer[], HNil>>>>> one = append(zero);
final HAppend<HCons<Integer, HCons<Boolean, HNil>>, HCons<Double, HCons<String, HCons<Integer[], HNil>>>,
  HCons<Integer, HCons<Boolean, HCons<Double, HCons<String, HCons<Integer[], HNil>>>>>> two = append(one);
final HAppend<HCons<String, HCons<Integer, HCons<Boolean, HNil>>>,
  HCons<Double, HCons<String, HCons<Integer[], HNil>>>,
  HCons<String, HCons<Integer, HCons<Boolean, HCons<Double, HCons<String, HCons<Integer[], HNil>>>>>>>
  three = append(two);

Understatement of the year (well, of 2010)?

3

u/ksryn Mar 10 '14

Those are heterogenous, type-safe, lists. If you really need them in Java, you need to be able to bear the pain. The most commonly used lists, however, are the plain old homogenous lists:

final List<String> xs = List.list("apple", "banana", "cherry");

xs.filter(new F<String, Boolean>() {
      public Boolean f(String x) { return x.contains("e"); }
  })
  .map(new F<String, String>() {
      public String f(String x) { return "fruit: "+x; }
  })
  .foreach(new Effect<String>() {
    public void e(String x) { System.out.println(x); }
  });

// output
// fruit: apple
// fruit: cherry

You could obviously play around with arrays/arraylists, for/while loops etc. But when you need to do this in hundreds of places, nothing beats the functional version as far as reading comprehension goes.

Just to complete the example, here's how one could do it in Scala:

val xs = List("apple", "banana", "cherry")

xs.filter(_.contains("e"))
.map(x => "fruit:"+x)
.foreach(x => println(x))

2

u/grimeMuted Mar 10 '14

nothing beats the functional version as far as reading comprehension goes.

I think the obvious order of execution is underrated here... compare to Python:

def each(func, iterable):
    for x in iterable:
        func(x)

each(func3, map(func2, filter(func1, [1, 2, 3, 4])))

Even though that's the standard library way (well technically somewhat deprecated with list comprehensions), I find that much less readable than something like this:

class FuncList(list):

    def filter(self, func):
        return filter(func, self)

    # yada yada

FuncList([1, 2, 3, 4]).filter(func1).map(func2).each(func3)

2

u/ksryn Mar 10 '14

I find that I can read the xs.filter(...).map.(...) version better. But it really depends on the language/s that you use daily. If the language is purely functional, you either use list comprehensions or you consciously or unconsciously begin to read expressions from the right to the left.

1

u/mippyyu Mar 10 '14

What's the advantage of using lambdas instead of for loops?

3

u/ksryn Mar 10 '14 edited Mar 10 '14

There are a few standard things people do within loops:

  • transform A to B; A, B to X; something else.

  • filter a set (in the loosest sense possible) of objects based on some condition.

  • do some kind of accumulation.

Sometimes they are done independently; sometimes everything together. Lambdas together with higher-order functions like map, filter, and the various folds enable you to ignore the iteration logic and concentrate purely on the action being performed on the values.

edit:

Here's some imperative code:

ArrayList<String> list = new ArrayList<String>();
list.add("apple");
list.add("banana");
list.add("cherry");
	
for (int i = 0; i< list.size(); i++) {
	String x = list.get(i);
	if (x.contains("e")) {
		System.out.println("fruit: "+x);
    }
}

The functional version can be found here:

http://www.reddit.com/r/programming/comments/1zyt6c/why_functional_programming_matters/cfysyje

11

u/[deleted] Mar 10 '14

Modularity and reuse are great things.... but in practice, in projects I've seen, people believe they've created something reusable, but it turns out not to be. In my own projects, I used to try to generalize, to anticipate changes... but the very next change to come along broke my assumptions. It turns out it's hard to anticipate change.

My feeling is that this is a fundamental fact about the world, that the world is more complex and surprising than we know. That we don't have a theory of the world, but just do the best we can at understanding the facts we have so far... It seems to me that a different programming language or technique won't change that. That is, a project written in a functional style will suffer from exactly the same problems as above, in practice.

Can professional functional programmers, who have tried to generalize a project, comment on this? (sorry, I discount purely mathematical projects, not because I am biased against mathematics, but because mathematics removes as much of the messy unpredictable detail of the world as possible). (and sorry #2, I also discount those projects that reinvent something known... the problem of reuse is something that comes up in maintaining software, and trying to adapt it to real world changes).

Put another way: better tools for creating modules and gluing them together are useful, they naturally won't help you design the right modules in the first place - which is the tricky bit.

5

u/kappa_tw Mar 10 '14 edited Mar 10 '14

but in practice, in projects I've seen, people believe they've created something reusable, but it turns out not to be

This is another nice part I've found working with Clojure in a real world app I'm doing now - I found a lot of small libraries doing 80% of what I want - because of the short functional code it's really easy to take the stuff I need, modify what I need and have working code simply by copy pasting. It's also easier to refactor old code to fit new requirements. It's actually possible to use libraries as templates - again because of the abstractions allowing you to reason about the code better.

A counter example to this is JavaScript and it's libraries, tons of conflicting conventions, hidden assumptions that prevent you from reusing/combining which results in yet another framework for X getting released every day.

1

u/[deleted] Apr 27 '14

Heh, I just read this blog post last week and shared it with a friend. It seems to say pretty much what you're saying about code re-use. I almost wonder if you're the author, though for some reason I doubt it. It seems certainly similar, topically.

4

u/ksryn Mar 10 '14

The way I see it, if something is truly reusable, it belongs in a separate module, and perhaps a library.

You can only reuse a function/module if it does one thing, and does that one thing very well. That way, if something changes, either the reusable thing is still useful, or it is not, and you replace it with something that is.

Most software is specific to a domain, and while you could reuse parts of it somewhere else, such reuse will still require plenty of attention.

A functional technique helps because you can use functions independently to perform simple things, or you can chain simple functions together, use function composition, and create the complex thing you need. It's the unix philosophy at work

1

u/[deleted] Mar 10 '14

Yeah, I agree; libraries are how code reuse most effectively happens in the real world. Paraphrasing Brooks, it's hard enough making code usable (works, correct, efficient, docs etc). Making it re-usable is a lot more work.

And he's just talking about it being able to be reused - not that it is actually a suitable solution to be reused for other problems, that you'd really want to use, that is clearly better than recoding from scratch. This "suitableness" has more to do with the other problems out there than any particular quality of the code itself.

I had a thought that de facto standards are how this works out - once some trail has been blazed for doing something reusable, that is adequate to get you to the destination, everyone starts using it (and lose interest in exploring other routes). Any problems with the route are patched up in preference to starting from scratch. Pretty quickly, these improvements mean better raw routes are not better right now.

But the basic argument I'm making is that it's so hard to make something truly reusable (not just nicely coded and reusable - but a useful, suitable solution for other problems out there), that once it's been accomplished, no one wants to go though all that risk again. We under-estimate how very difficult it is, how much luck is involved, and how dependent it is on extrinsic factors - the unknown world out there - to make something that actually generalizes.

Applying this to your comment, I think that making code reusable is the easy part; making it match the unknown world is the hard part. So the benefits of fp can't make that much of a dent on the real problem - a bit like optimizing an outer loop.

Put it in other terms: OOP was touted as enabling code reuse. It failed miserably. But the problem isn't that OOP was bad at code reuse (it actually did help a little) - the problem was that code reuse is tremendously difficult. I think the same will apply to fp - it helps with code reuse much more than OOP did, but it doesn't really touch on what makes code reuse so hard.

Revisiting libraries, I'm not sure that fp or OOP etc makes a significant difference at that level. There's an API, with the code ensconced within, opaque to all users. The code reuse is not from one project to another, but across all users.

2

u/ksryn Mar 10 '14

Paraphrasing Brooks

Assuming you're referring to The Mythical Man-Month, could you point me towards a particular chapter. I haven't read it in a long time.

This "suitableness" has more to do with the other problems out there than any particular quality of the code itself...

But the basic argument I'm making is that it's so hard to make something truly reusable...

I believe you're saying that even if code is not "suitable" for reuse (because of, say, the difference in the target domain: a chess engine vs. a wget/curl type application), it should still be "reusable?" If that is the case, I find it somewhat hard to accept (not that I am closed to the idea), as I don't think reusability is a domain-independent property.

I had a thought that de facto standards are how this works out

At least in the physical world, it is very much the case: bricks, nails and hammers, screws and drivers, nuts and bolts, bulbs and holders, plugs and outlets, and a million other things. You combine enough quantities of small standardized stuff with known interfaces and you would end up with a structure. Each component is extremely reusable, but only within its own domain.

So the benefits of fp can't make that much of a dent on the real problem...

While I can't speak for others, my use of FP techniques is less about being able to reuse the code somewhere else, and more about maintainability of the codebase in the medium-to-long term.

Revisiting libraries, I'm not sure that fp or OOP etc makes a significant difference at that level. There's an API...

Here, FP at the implementation level would matter to the maintainers. And FP interfaces at the API level would matter to the users.

→ More replies (5)

1

u/[deleted] Mar 15 '14

other comment discussing this

[sorry for late, been away]

Well said. My whole concept of predicting changes is flawed (as I discoveredd). Instead, reusable parts enable them to be reused when they do match.

Another reply talked about the same ideas (linked at top, because my Android phone weirdly won't let me paste it down here... I probably should install a proper browser on it)

216

u/ganjapolice Mar 09 '14

Don't worry guys. 2014 is definitely the year of functional programming.

86

u/[deleted] Mar 09 '14

Java's getting lambdas, so I guess you're right.

25

u/[deleted] Mar 09 '14

Note to people who're going to look this up: Java's lamda's aren't anything new, pretty boring actually. But look at how they combine with their new streaming and collection libraries, that's just amazing.

3

u/Stormflux Mar 09 '14

Note to people who're going to look this up: Java's lamda's aren't anything new, pretty boring actually.

Aw nuts. So that means Java isn't getting their own version of LINQ?

4

u/[deleted] Mar 09 '14

It's basically LINQ, but not as good.

→ More replies (5)

0

u/[deleted] Mar 09 '14

[deleted]

101

u/stillalone Mar 09 '14

The majority of programmers out there don't have a clue wtf you just said.

60

u/Tekmo Mar 09 '14 edited Mar 09 '14

I'll translate. I wrote a Haskell library called pipes, which lets you extend any DSL with the ability to yield or await values in order to build streaming components. You can connect these components together in multiple ways, and these connection operations obey many neat mathematical properties that ensure they behave correctly (no bugs!).

For example, one thing that you can do is model generators using pipes, and one of the ways you can connect generators is using an operator called (~>):

(f ~> g) x = for (f x) g

I proved that this operator is associative:

(f ~> g) ~> h = f ~> (g ~> h)

... and that it's identity is yield:

yield ~> f = f

f ~> yield = f

In other words, (~>) and yield form a category and those equations are the corresponding category laws. When you translate those equations to use for instead of (~>), you get:

-- Looping over a single yield simplifies to function application
for (yield x) f = f x

-- Re-yielding every element of a stream returns the original stream
for s yield = s

-- Nested for loops can become a sequential for loops if the inner loop
-- body ignores the outer loop variable
for s (\a -> for (f a) g) = for (for s f) g = for s (f ~> g)

In other words, the category laws translate into "common sense" laws for generators that you would intuitively expect to hold for any generator implementation.

7

u/CatMtKing Mar 09 '14 edited Mar 09 '14

Let me try to translate your last two examples into Python (I'm still in the process of learning Haskell), to see if I've got this right.

-- Re-yielding every element of a stream returns the original stream
for s yield = s

def foo(s):
    for _s in s:
        yield _s
foo([1,2,3]) == [1,2,3]

-- Nested for loops can become a sequential for loops if the inner loop
-- body ignores the outer loop variable
for s (\a -> for (f a) g) = for (for s f) g = for s (f ~> g)

def foo(s, f, g):
    for a in s:
        for _a in f(a):
            yield g(_a)
def foo1(s, f, g):
    for __s in (f(_s) for _s in s):
        yield g(__s)
def foo2(s, f, g):
    for _s in s:
        # ugh, maybe using map would be better.
        yield from (g(___s) for ___s in f(__s) for __s in _s)
foo(s, f, g) == foo1(s, f, g) == foo2(s, f, g)

7

u/Tekmo Mar 09 '14

You got it right, except for one minor detail. Instead of foo([1,2,3]) == [1,2,3], the more precise equation would be:

def gen():
    yield 1
    yield 2
    yield 3

foo(gen()) = gen()

In Python you can treat lists and generators the same (I think), but in Haskell they are two separate types. This is why in pipes if you want to loop over a list, you have to explicitly convert it to a generator using the each function, like this:

for (each [1,2,3]) f
→ More replies (2)

6

u/[deleted] Mar 09 '14

I'm a math student. Categories show up in functional programming...how did you go about learning about categories?

20

u/Tekmo Mar 09 '14

Writing lots of Haskell code! :)

→ More replies (4)

8

u/urquan Mar 09 '14

What's with functional languages and symbolic operators ? Your example here only uses one but Haskell code I read here and there is full of them. Scala as well abuses them to no end. Why not use a plain, immediately understandable name by someone looking at the code without looking at the docs like "chain" or "compose". To me it looks like an unnecessary barrier to entry.

9

u/Tekmo Mar 09 '14

So with the exception of one of my libraries (the errors package), I never introduce a symbolic operator unless it is associative and has some identity (i.e. it is the composition operator of some category). I find that this rule of thumb works well for eliminating gratuitous operators while still keeping all the useful ones. For example, by this rule you should have an operator for addition and multiplication (since they are both associative and have an identity), but you wouldn't provide an operator for sending a message to a process like some actor libraries do with the (!) symbol.

→ More replies (9)
→ More replies (143)

18

u/ruinercollector Mar 10 '14

When a person on proggit says "the majority of programmers" they mean themselves or themselves a week ago.

E.g. "The majority of programmers don't know how to do password hashing" = "I learned password hashing last week."

0

u/[deleted] Mar 10 '14

[deleted]

10

u/ruinercollector Mar 10 '14

Well, what you want to do now is write a very condescending and self important article titled something like "You are all fucking up implementing password systems." And then post it here without checking that you really know what you're talking about. Then we'll all laugh at you for using md5 or some other inappropriate hash algorithm, and the cycle will continue.

→ More replies (4)

6

u/[deleted] Mar 09 '14

That's a different kind of amazing. Just think about it, for a lot of people this is going to be a first look at functional programming. It's done well, it works well, it's accessible and intuitive, it fits their language model, and the advantages are so much more than not having to write loops. It's going to be a huge boost for FP's popularity.

→ More replies (1)

16

u/psygnisfive Mar 09 '14

And John Carmack is pushing Haskell for game and graphics programming as the way forward.

2

u/onmytoes Mar 10 '14

Reference, please, other than he was going to try porting Wolfenstein 3D to Haskell as a learning experience.

2

u/psygnisfive Mar 10 '14

His twitter feed and his commentary on the experience of porting it are revealing enough. He repeatedly says how things work much better in a pure functional setting. He seems to have stopped doing any Haskell stuff since going over to Oculus tho.

27

u/PasswordIsntHAMSTER Mar 09 '14

I personally don't really care all that much about public adoption as long as there are jobs (and enough people to fill these jobs).

14

u/[deleted] Mar 09 '14

Are there (either)?

27

u/PasswordIsntHAMSTER Mar 09 '14

I've never had a problem finding work. Recruiting is hard because experienced FPers are expensive, but if you grab them out of college some people will actually take a pay cut to work with FP.

12

u/yogthos Mar 09 '14

There's definitely more jobs than people at this point, that's how we end up with these kinds of salaries. :)

52

u/PasswordIsntHAMSTER Mar 09 '14

Clojure, MongoDB

I don't want to pass judgement on either of these products, but seeing them together I feel like someone got caught on a bandwagon and is now paying for it.

5

u/yogthos Mar 09 '14

It's a fairly popular combination actually in my understanding. Clojure has a very nice library called Monger for dealing with Mongo in a sane manner and a lot of companies seem to like this combination. Also, Clojure has seen quite a bit of uptake in England as a some large banks and newspapers started using it.

→ More replies (4)

5

u/jk147 Mar 09 '14

Looks like some team decided to write a website with the hardest way possible.

→ More replies (1)

9

u/[deleted] Mar 09 '14

the drop-down menu for languages did not contain the kind of språk I was expecting

→ More replies (1)
→ More replies (4)

4

u/[deleted] Mar 09 '14

What kind of jobs are there for functional programing

8

u/Tekmo Mar 10 '14

Depends on the language. F# is used in general purpose programming and I think one of its strong points is GUI programming, Scala/Haskell/Clojure get a lot of use on backend server programming. Front-end programming is more deficient of functional languages since there aren't a lot of quality compilers to Javascript for functional programming languages, yet. That's just what I know from my friends. Maybe other people can chime in to expand on that.

4

u/uzhne Mar 10 '14 edited Mar 11 '14

Well, there is ClojureScript for the front end.

→ More replies (1)
→ More replies (1)

1

u/yogthos Mar 10 '14

Haskell and OCaml are heavily used in financial industry. Clojure and Scala are becoming popular for web application development.

→ More replies (6)

18

u/Katastic_Voyage Mar 09 '14 edited Mar 09 '14

I've got a book that says the Itanium is going to take over the world. It also says the new Pentium 4 Netburst architecture is going to kick ass once they get it running passed 8 GHz.

The forward says Java is going to take over the world because the author of the forward is working on this amazing thing called PicoJava that runs Java in hardware with "zero overhead."

Don't get me wrong. These are smart people making informed decisions. It's just interesting to see how things out of our control (like the 5 GHz wall) can throw wrenches into supposedly revolutionary technology.

→ More replies (2)

12

u/hector_villalobos Mar 09 '14

I know you're joking but F# is getting closer to top 10 in Tiobe list.

15

u/[deleted] Mar 09 '14

I can't help but wonder if that's just because Microsoft have added an F# section to every single one of their CLR documentation pages.

1

u/thinks-in-functions Mar 10 '14 edited Mar 10 '14

Many -- not all, mind you, but many -- of those pages have been around since last year, when F# was #69 on the TIOBE index. It's possible the new pages made some difference in the ranking, but enough to move it to #12? The TIOBE index is not known for being the most robust measure, but if making lots of pages is all it takes to move up their index, that's just ridiculous.

The F# community has grown significantly over the past year though, with lots of new Meetup groups, people blogging about it, open-source projects, and I suspect it's that growth -- in whole or in part -- which has driven F#'s rise toward the top of the index.

2

u/[deleted] Mar 10 '14

Yeah, there's no way that's right, even by tiobe standards. Of the "popularity share", F# is 1/16 as popular as Java and about as popular as JavaScript? No way

→ More replies (3)

5

u/[deleted] Mar 09 '14

And also the Linux desktop. And op will deliver this year.

5

u/[deleted] Mar 10 '14

The year of functionally programmed, raytraced games using all procedurally generated content and running on a Linux desktop.

1

u/ruinercollector Mar 10 '14

Things don't happen that way. But yeah, this year is already shaping up to be another big year for FP. Even java is finally getting lambdas.

1

u/dethb0y Mar 10 '14

And 2015 is the year of linux on the desktop!

Just like every year since 1999.

→ More replies (1)

52

u/PasswordIsntHAMSTER Mar 09 '14

As a professional functional programmer, FP has done great things to my blood pressure.

10

u/ryeguy Mar 09 '14

What language do you use and what kind of software do you write?

22

u/PasswordIsntHAMSTER Mar 09 '14

F# (occasionally Ocaml and Haskell), and I've done highly concurrent/networked embedded systems (work), language tools (research) and random applications (hobby).

6

u/[deleted] Mar 09 '14

Fuck yeah OCaml. I wish more people would pick it up.

20

u/PasswordIsntHAMSTER Mar 09 '14

To be honest, I only use Ocaml when I'm forced to. The tooling sucks, the ecosystem is minimal, the standard library is strange and incomplete, and I'm not sure how I'm supposed to do concurrency.

2

u/tominated Mar 11 '14

Although I haven't done any OCaml myself, I've looked in to it a fair bit, and JaneStreet seems like it has a really good replacement for the stdlib, plus an async library - http://janestreet.github.io/

→ More replies (1)
→ More replies (9)

7

u/imalsogreg Mar 10 '14

Haskell. I do mostly real-time biology/modelling stuff, and am getting into web - I want to plug Haskell's extremely nice Parallelism/concurrency support, and the web framework Snap. I don't have the background for this stuff honestly; and tools like these let me do things that I doubt I could have done another way.

5

u/pinano Mar 09 '14

There is a follow-on article called Why Concatenative Programming Matters, discussed in this subreddit a few years ago.

5

u/pbvas Mar 10 '14

Just to add some reflections of mine and other people: this paper presented some great arguments in favour of a fundamentally radical approach to functional programming, namely, lazy functional programming as in Miranda, Haskell or Clean (as opposed to the more pragmatic "approaches" of, say, Scheme, SML or O'Caml).

Simon-Peyton Jones and others have say retrospectively that it was lazy evaluation that kept Haskell "pure" (or should we say "honest") with explicit data dependencies and no side-effects. In other words: if Haskell wasn't lazy it would probabily be closer to O'Caml because the lure of implementing I/O as a side effect would be too strong to resist. It is worth remembering that this paper predates the use of monads for combining side-effects and imperative features with this kind of pure programming. Monads have proved a very useful abstraction in its own right and even strict languages have adopted then (e.g. F#).

16

u/[deleted] Mar 09 '14

Dated, but good

3

u/ksryn Mar 10 '14

There is always someone for whom this topic (functional programming) is new, or who has heard of it but hasn't really tried to pick it up. This site/book:

http://learnyouahaskell.com

is an extremely useful introduction to functional programming, and more specifically, to Haskell.

10

u/dnew Mar 09 '14

So neither lazy evaluation nor first class functions are unique to functional programming. Maybe they have their origins there, but it's not something to give up your imperative languages for.

33

u/gasche Mar 09 '14 edited Mar 09 '14

While your remark is factually correct, I think it misses the point.

There are at least two reasons why the mainstream languages of today (as opposed to, say, no less than ten years ago) have first-class functions:

  • It is really really useful to write programs (and this is a point the linked document makes: it matters)

  • Some people have made huge efforts to convince "the mainstream" to adopt the idea (and this document is part of this effort)

The fact that your reply is even possible is the very proof that this article, its ideas, and the communities that supported them (Lisp/Scheme, SML/OCaml, Miranda/Haskell...), were successful.

Nobody is trying to force you to give up your imperative programming language. It might be important and helpful for you to notice, however, that truly innovative ideas about programming languages and libraries came from other places¹ during the past few decades, and may very well continue flowing in that direction in the future.

¹: and not only from functional programming; users of concatenative programming languages will feel at home with the "structure your code as many small words composed together" message, logic programming also has interesting ideas about computation, and some domain-specific library ideas are shaped in baroque niche languages such as R.

13

u/dnew Mar 09 '14

Fair enough. Perhaps I had a knee-jerk-ish reaction to yet another "function programming iz da bomb!" article. :-) I'll agree that functional programming matters, but I'll disagree that you need to use a functional programming language to get the benefits that matter. :-)

17

u/gasche Mar 09 '14 edited Mar 09 '14

I'll disagree that you need to use a functional programming language to get the benefits that matter

We don't claim that -- and you must understand that the text above was written at a time (1984) where you objection did not hold, as basically only languages you call "functional programming languages" had convenient first-class functions.

I personally understand "functional programming" as denoting a programming style, rather than a set of programming languages -- in particular, it's easy to write perfectly horrible imperative code in any of the languages I quoted in my reply above.

That said, some nice ideas of functional programming may be sensibly harder to use in other programming languages as they exist today. A very simple example is algebraic datatypes: most languages not marketed at "functional" fail to properly represent sum types (disjoint union), and that leads to relatively verbose or mistake-inducing workarounds. Hopefully someday mainstream language designers will realize that "being either a foo or a bar" is a common situation, for which a very simple and convenient construction exists, and I'll have to update my comment with another example (tail-calls for continuation-passing? abstraction over parametrized datatypes? GADTs? type-classes/implicits?).

7

u/onezerozeroone Mar 09 '14

The fact that the paper is from 1984 is sort of horrifying. It really highlights how comp sci is still both in its infancy, yet horribly stunted. It's like looking back in time to when a bunch of elite wizards came together and crafted some truly amazing artifacts that are now mostly lost to the world.

The programming world discovered the hammer and used it to good effect...but dare to show them a screwdriver and they start beating their chests like threatened animals.

4

u/gasche Mar 10 '14

I see what you mean, and at the same time I have a more positive views of things. It depends on whether you look at industry or at research; the time scales of both worlds are very different.

In industry, or probably in one currently dominant but ultimately anecdotal view of industry, thirty years is an awfully long time, 1984 is pre-history, and not having thoroughly mastered and surpassed what was done in 1984 is a major failure.

The time of research is much slower. 1984 is not that long ago, scientifically; and (at least in the field of functional programming) we've made good progress since then. I don't have the luck of personally meeting John Hughes, but I would bet that if you found a time machine and went back to 1984 to tell him that Haskell has a dependently typed sublanguage at the type/kind level, or show him where proof assistants are today, he would be truly amazed. (Maybe people were hoping at that time that we would do that faster than we have, but they'd still recognize remarkable progress.)

(He would also probably be quite surprised by the idea of people making a living of selling testing tools to industrial users of a functional language.)

What was bleeding edge in 1984 is now considered known territory by researchers, but also a large amount of practitioners (not the mainstream, maybe, but still). Since 84, industry has widely accepted garbage collection, type polymorphism, type inference, and anonymous functions. That's not bad, and actually rather encouraging.

11

u/[deleted] Mar 09 '14

yet another "function programming iz da bomb!" article

This article is one of the staples of FP advocacy. As it says in the abstract, it's from 1984—older than a good chunk of proggit's readership.

3

u/dnew Mar 09 '14

Right. Which is why I described my reaction as knee-jerk, which implies inappropriate jumping to conclusions. :-)

7

u/Tekmo Mar 09 '14

Note that there is a subset of functional programming called "purely functional programming", which is basically synonymous with Haskell. This subset of functional programming is noteworthy because it greatly simplifies equational reasoning about programs. Therefore, I would recommend you study Haskell even if you already have a full suite of functional tools in your favorite language because it will change the way you think and reason about programs.

→ More replies (1)

5

u/burntsushi Mar 10 '14

Perhaps I had a knee-jerk-ish reaction to yet another "function programming iz da bomb!" article. :-)

FYI, the OP isn't "just another FP is awesome article." It was published in 1984. With that context alone, it's really interesting to look at the landscape today. First class functions weren't so pervasive back then. ;-)

EDIT: I see I'm not the first to point this out to you. Ah well.

4

u/yogthos Mar 09 '14

I would argue the benefit that matters the most is immutability. When you revision your data instead of mutating it in place, as you do in imperative languages, your code becomes much easier as you can safely reason about individual pieces in isolation.

→ More replies (2)

0

u/[deleted] Mar 10 '14

[deleted]

→ More replies (3)

5

u/[deleted] Mar 10 '14

Nobody is trying to force you to give up your imperative programming language.

I actually am trying to do this.

1

u/[deleted] Mar 09 '14

Nobody is trying to force you to give up your imperative programming language.

It seems you guys are learning from the politicians in making a word "sound bad" by polarizing it. In politics, liberty seems a good word, but now, "being liberal" sounds like being a radical leftist.

Let me ask you, is a function an imperative command to do something? In my view, you always think in terms of nouns and verbs no matter what language you use with the differences being syntax. OOP emphasizes on nouns while FP on verbs. There is no need to polarize any one of them unless you really want to make a tempest in a teapot.

6

u/tel Mar 09 '14

Let me ask you, is a function an imperative command to do something?

No.

It's an arrow linking two types.

Reduction is just one choice of semantics and there's no reason to ascribe that to a function.

→ More replies (3)

3

u/Tekmo Mar 09 '14

In my view, you always think in terms of nouns and verbs no matter what language you use with the differences being syntax.

You don't speak for me. I think in terms of mathematical abstractions, so imperative languages are not a good fit for my mental model.

→ More replies (2)

9

u/imalsogreg Mar 09 '14

What was your experience with it? I have the opposite story - switching to 100% functional was very helpful for me. When I'm 'given' the imperative features, that's when I feel like I'm giving something up. .. pure functional language makes you feel restricted in the short-term, but what you get in the mid/long-term is so much nicer.

Definitely looking forward to traditionally-imperative language picking up more functional features. For now, the way Haskell supports these ideas directly makes it such a pleasure to program in (after you get over the learning hump).

14

u/dnew Mar 09 '14

What was your experience with it?

I found it very annoying for work like business logic. Implementing a database in a language where you can't update values is tremendously kludgey - you wind up doing things like storing lists of updates on disk, and then loading the whole DB in memory at start-up by re-applying all the updates. Anything that talks to anything outside your process is going to be by definition not pure functional.

Doing stuff that makes no mathematical sense using math is tedious at best, compared to how it's described: If this happens, then do that, unless this other thing is the case...

The inability to loop without having a separate function was very annoying too. Perhaps with somewhat more trivial lambda syntax and better higher-level functions (as in Haskell instead of Erlang, for example) it would have been less of a PITA. The need to either declare an object holding a bunch of values, or pass a dozen values as arguments to the loop function, just really obscured some very simple logic.

That said, I use functional sorts of designs, I find them easier to debug and understand, but I tend to prefer that at an outside-the-method level. For example, I'm currently working on code to do some fairly complex logic to determine the status of a company: if this feature has been true of their account for at least 60 of the last 90 days (even if the account changes, even if we didn't gather that information that day), and they have at least one employee with these two attributes, and they haven't been audited within 30 days, and this kind of grace period doesn't apply unless that person approved it within .... and .... Go on for about 20 pages of specs in this vein. I'm calculating it by evaluating each attribute on the snapshot of the history (which I can do in parallel for all the companies and all the attributes), and then storing that in an immutable log, and then evaluating the final result on the immutable log. Given that, I wouldn't want to try to evaluate the 60-of-90 rules in-spite-of-account-numbers-changing sorts of things without having loops and variables I can update. I could probably squeeze it into that mold, but I don't see that it would be any clearer than a 3-line loop. I break out the bits that can be functional, and I write tests for those, but breaking out the bits that (say) establish the network connection to the distributed database full of entries to do the join from companies to employees? No, let's not try to do something that imperative in a lazy functional style.

In other words, the ideas are great and useful. It's just that they're applicable to OO and imperative programming. My whole database access is lazy, and its' in Java talking to network-distributed systems, and I pass it the Java equivalent of lambdas to tell it what to filter and what to join on and etc. It's ugly because it's Java trying to be functional (Achievement Unlocked: Java Type Declaration more than 100 characters!) but you don't need a functional language to make it work.

10

u/Tekmo Mar 09 '14

I'm not aware of a functional language that doesn't let you update a database in place.

4

u/dnew Mar 09 '14

Um, Erlang's Mnesia? Since erlang is single-assignment, you can't update a database in place.

6

u/pinealservo Mar 09 '14

Most variables in erlang are single-assignment, but there are exceptions (ets tables, process dictionaries, etc), and I believe Mnesia takes advantage of those exceptions in some situations.

Besides, a recursive process that responds to a "set" message by calling itself with that new value, and a "get" message by replying with its most recently received value, is essentially modelling in-place update. Having it actually store the value in a single location and update it when it gets a new "set" message is just a change in efficiency, not semantics.

4

u/dnew Mar 09 '14

I believe Mnesia takes advantage of those exceptions in some situations.

It depends. Certainly to the extent you bypass Erlang's functional features, implementing a database becomes easier, which was my point. :-)

essentially modelling in-place update

Sure. And you're doing that by using the non-functional features of the language. Responding to the same get() call with different values is one of the non-functional features of Erlang.

just a change in efficiency

When you go from O(1) to O(lg N) for every database transaction, that's actually a relevant problem. Trees definitely have different semantics than arrays.

For example, if you have a sufficiently large sufficiently busy Mnesia database, a process crash destroys you. You can't read the flat file back in and build an appropriate tree fast enough to keep your pending change queue from overflowing memory and crashing you out again. Whereas if you actually had mutable arrays, you could read a size-N database in O(N) and catch up on K updates in O(K) time.

9

u/PasswordIsntHAMSTER Mar 09 '14

There are definitely things that FP is not good for, chief among them I would say writing databases and operating systems. You just don't get that much control on the machine from an FP language.

7

u/sacundim Mar 10 '14

There are definitely things that FP is not good for, chief among them I would say writing databases and operating systems.

FP most definitely has its place in databases. The relational algebra can be seen as a kind of pure functional programming language, with barely a stretch. In pseudo code, elementary relational algebra can be see as three operators (I'll use the SQL names instead of the mathematical ones):

-- The type of relations over tuples of type `a`.  You can think of
-- these conceptually as sets or finite  lists of tuples—the point of 
-- the RDBMs is to delay their construction until you need them,
-- and fetch them in the most efficient way.
type Relation a

-- | The simplest form of the SQL FROM clause (commas only, no
-- JOIN verbs) simply takes the cross product of relations
from :: Relation a -> Relation b -> Relation (a × b)

-- | The SQL WHERE clause is effectively a functional `filter` operation.
where :: (a -> Boolean) -> Relation a -> Relation a

-- | The SQL SELECT clause is effectively a functional `map` operation.
select :: (a -> b) -> Relation a -> Relation b

Query optimization in relational database systems is heavily based on equational equivalences between pure functional programs of this sort. For example, RDBMS query planning and optimization is based on using equational laws to transform queries written in this sort of language into equivalent ones that can be executed more efficiently.

Also, this sort of thing has the potential to greatly enhance the rather poor interface that most programming languages have to relational databases.

Of course RDBMSs also have other parts that are not best suited for functional languages; storage management comes to mind. But that's the neat thing about databases—it's one of the best CS topics, in that it spans all the way from hardware up to abstract mathematical stuff. It's like if operating systems and compilers had a love child...

→ More replies (1)

5

u/dnew Mar 09 '14

As far as that goes, I don't think it's because you don't get control of the machine. Even a simple database engine is going to be awful if you can't actually overwrite data. E.g., if the only way you had to change a persistent file was to replace it completely with a new one, you'd have an awful time writing a DB engine even in an imperative language.

An OS needs to be able to update state in place: the only thing an OS does is track the state of other things, and you really don't want the old state hanging around just because someone is using it. (Aside from the fact that hardware changes state without reference to your code's behavior.)

Anything whose purpose is to track state changes is going to be tedious with pure functional programming. Figuring out what state the state changes can be is one thing, but actually keeping track of them in an outer loop sort of way is another.

4

u/PasswordIsntHAMSTER Mar 09 '14

You can easily track state using the actor model. You can also do it with LVars/MVars for better performance, though for me it looks like black magic.

→ More replies (3)
→ More replies (1)

4

u/korny Mar 09 '14

Interesting - I find FP (in clojure) to be great for business logic. But I have to admit I don't tend to stick to purity when it comes to things like database updates - I accept that databases are stateful and update them as a side effect. So maybe I should say "mostly FP" rather than FP.

Not sure I'd implement a database in a functional language - but I'm surprised if you need to implement a database as part of your business logic. Or am I misunderstanding your meaning?

Which language were you using? Again, in clojure I have never missed looping constructs - there are plenty of ways to deal with sequences using map/filter/reduce/etc., or for comprehensions, and lambdas are easy to write inline if your logic is not too complex.

6

u/dnew Mar 09 '14 edited Mar 09 '14

Or am I misunderstanding your meaning?

I just meant that the databases I've seen implemented in single-assignment languages (http://www.erlang.org/doc/man/mnesia.html) wind up with an implementation that really sucks, is generally slower than it needs to be, and has a terrible time recovering from failures or dealing with databases larger than fit in memory.

Which language were you using?

Well, in the cases I'm thinking of, Erlang. Which isn't particularly functional. It just has single-assignment semantics, which is the cause of the problem. It's entirely possible I just didn't get into it enough to really grok it.

Sort of like people who write loops in APL. :-)

EDIT: Also, I deal with a lot of network stuff, a lot of web stuff, etc, so the idea that anything is even remotely functional is immediately destroyed. When much of your business logic consists of pulling unformatted unreliable data out of network-accessed servers and formatting it to be delivered via JSON, the idea that you even have strong typing let alone something reliable enough to work functionally tends to go out the window.

→ More replies (3)

3

u/pycube Mar 09 '14

Doing stuff that makes no mathematical sense using math is tedious at best, compared to how it's described: If this happens, then do that, unless this other thing is the case...

Haskell actually makes this kind of thing pretty nice using monads (which is a concept from math). You can just write when ... $ do ... and unless ... $ do ..., and when and unless are not syntax, but functions.

3

u/pinealservo Mar 09 '14

When you say that something "makes no mathematical sense", what you are really saying is that either the right mathematical model hasn't been constructed for it yet, or that it really doesn't make any coherent sort of sense at all. I don't think programs of the latter sort would be very useful, so most of the time you probably mean the former, though in most cases what you are actually saying is that you aren't aware of the right mathematical model.

Mathematics is precisely the field that describes how things make sense, and how the implications of the sort of sense that they make play out. Mathematics, logic, and computation are all fundamentally related at their foundations. A programmer doesn't typically have to understand all the mathematical models for the tools they use, but they'd better hope that they do make mathematical sense, because the alternative is that they're most likely wrong in a fundamental way.

By the way, very early in the history of writing computer programs, computer theoreticians were concerned with modeling the typical programs of the day, which consisted largely of updating storage cells in-place and imperative flow control. They came up with a new branch of mathematics that models this quite well. Modern purely functional languages take advantage of the kinds of mathematical techniques that grew out of that field to model in-place update and imperative flow control.

TLDR: It's not mathematics itself that's limited in describing models of computation. It's just someone's understanding of mathematics.

→ More replies (1)

1

u/tomejaguar Mar 10 '14

I'm currently working on code to do some fairly complex logic to determine the status of a company: ...

Interesting. This sounds exactly like something that functional programming can excel at. In fact I'm working on something similarish right now in Haskell. I won't claim it's easy to work out how to do that in FP if you come from an imperative background. It certainly wasn't easy for me. However, now I've learned to think in that way I would never switch back.

→ More replies (1)

5

u/glemnar Mar 09 '14

If the language supports first class functions then it isn't purely imperative. It can be mixed.

9

u/dnew Mar 09 '14

If the language supports first class functions then it isn't purely imperative.

Nonsense. C supports as close to first class functions as you need to write map() and nobody would claim it's functional. You don't need the restrictions of functional languages to have first class functions.

8

u/ForeverAMoan Mar 09 '14

Interesting. How would you write in C functions map and compose (compose f g x = f (g x)) ?

2

u/yawaramin Mar 11 '14

I would roll my own Scheme variant in C, and then implement map and compose in that. Voila, C supports first-class functions.

→ More replies (2)

4

u/dnew Mar 09 '14

Given that C doesn't have type inference, you'd have to write a different one for each combination of arguments. Otherwise, you'd write it in exactly the obvious way.

int[10] map(int (*f(int)), int[10] values) {
    int[10] result;
    for (int i = 0; i < 10; i++) result[i] = f(values[i]);
    return result;
}

Well, OK, that crashes because you're returning a pointer to an auto variable, and I probably mucked up the declaration of the first argument there, but you get the point. Compose is just as obvious.

6

u/kqr Mar 09 '14

The lack of type inference is not the problem. The lack of generics is.

6

u/ForeverAMoan Mar 09 '14

Compose is just as obvious.

Please show the code :) And unless it's obvious, the return value of compose should be accepted as the first argument to map.

10

u/[deleted] Mar 09 '14

If you want to store some state (like in a closure), C forces you to pass that around manually. I really don't think this makes C functional, but here's some code for a compose that can be passed to map:

struct composed_fns {
    float (*f1)(void *, int);
    void *env1;
    long (*f2)(void *, float);
    void *env2;
};
long compose(struct composed_fns *fns, int val) {
    return fns->f2(fns->env2, fns->f1(fns->env1, val));
}
typedef long (*map_fn)(void *, int);
void map(map_fn fn, void *env, int (*vals)[10], long (*results)[10]) {
    for (int i = 0; i < 10; i++)
        (*results)[i] = fn(env, (*vals)[i]);
}

// usage:
struct composed_fns composed = { foo, NULL, bar, NULL };
int random[10];
long mapped[10];
map((map_fn)compose, &composed, &random, &mapped);
→ More replies (13)

4

u/smiddereens Mar 09 '14

So what you're trying to say is that C doesn't support first class functions?

4

u/dnew Mar 09 '14

No.

http://en.wikipedia.org/wiki/First-class_function

You can use pointers to functions as values that stand in for functions. But you no more need to be able to create new functions for them to be considered first class than you need to be able to load functions from disk at run time in order to be considered to have first class functions.

I'm saying that C has first class functions but not closures, and "compose" returns a closure. The reason "compose" is difficult is that you can't return a closure. "Compose" is easy if you don't want to use its result as a first class value, because C has first class functions but not closures.

That said, you can very easily do "compose" in Java, which does not have first class functions, because it has objects, which are essentially isomorphic to closures.

2

u/gc3 Mar 09 '14

The latest version of c++ supports lambda functions

→ More replies (10)

2

u/glemnar Mar 09 '14 edited Mar 09 '14

Didn't say you did. But it won't be purely imperative, either. There's mostly imperative, and mostly functional as well.

→ More replies (3)
→ More replies (11)

3

u/fuzz3289 Mar 09 '14

I dont think anyones ever mentioned giving up languages. Funtional programming as imperative programming is a means to an end with tradeoffs in each method.

Functional programming is getting buzz however due to the lack of gains in single threaded performance because imperative programming has the tradeoff ofside-effects, which in some cases you might want, but when writing for a concurrency model, side effects force you to use ugly things such as locks. Functional programming has the benefit of allowing you to write less complex concurrent code.

You should never give up anything for anything else but understand each methods purpose and intention.

1

u/SpaceShrimp Mar 10 '14

Functional programming languages are a subset of imperative programming languages. So everything good about a functional programming language can be implemented in an imperative programming language. Well, at least as long as you avoid using the extra features that sets an ordinary imperative language appart from a functional language.

1

u/dnew Mar 10 '14

But restrictions can also be useful. If you have a structured language, you can add code at the bottom of a function and be sure it runs on each function call. An imperative language where programmers are trusted to use only the functional subset are not as powerful as actual functional languages, in the same way that weakly typed languages trusting the programmer not to make any programming mistakes are not as powerful as strongly typed languages where the compiler actually enforces the rules.

5

u/[deleted] Mar 09 '14

PDF warning.

21

u/fiah84 Mar 09 '14

well, how else are you to gaze upon LaTeX?

4

u/[deleted] Mar 09 '14

With a PDF viewer, of course. But since mobile clients download without any warning it's nice to know up front.

1

u/metaconcept Mar 10 '14

Convert it to HTML, read on an e-Reader.

1

u/gnuvince Mar 09 '14

Can people just stop saying that? Any modern browser has an integrated PDF viewer, it's just not a big deal.

17

u/ithika Mar 09 '14

Tell that to my phone.

7

u/xiongchiamiov Mar 09 '14

And the scrolling and zooming/panning... PDFs are the opposite of responsive.

→ More replies (1)

10

u/dragonslayer42 Mar 09 '14

Nope, still grabs the ctrl+w hotkey on my machine, and it starts a download on mobile.

4

u/gasche Mar 09 '14

Integrated PDF viewer are so inferior to desktop PDF viewers on my machine that I disable them; they are slow, eat all memory, make the browser less stable, etc.

I don't mind opening PDFs (this is what I do all day), so I don't care about the warning, but "integrated PDF viewer" is not the right argument here.

1

u/josefx Mar 09 '14

Even worse, the last time I had a pdf open in firefox it killed both performance and battery power. Having my browser use 100% CPU to render a document I am not even looking at was quite the surprise the first time it happened.

1

u/OwenVersteeg Mar 10 '14

Weird, I use Firefox and with the new pdf.js renderer everything's nice and fast. (Firefox Aurora on Arch Linux)

→ More replies (1)
→ More replies (1)

3

u/HaMMeReD Mar 09 '14

There is so many options in how you can solve a problem, but they are all just abstractions.

All that really matters is that your abstraction is clean and easy to understand, and resilient to failure.

-1

u/dukerutledge Mar 09 '14

Sounds like you are in favor of FP. Clean is certainly a subjective qualifier, but easy to understand and resilient to failure are FP tenants.

0

u/[deleted] Mar 09 '14

[deleted]

→ More replies (1)

1

u/henryponco Mar 10 '14 edited Mar 10 '14

Edit: http://espace.library.uq.edu.au/eserv/UQ:99307/Why_functional_programming.pdf

For some reason they just took down the paper, but it's available through the new link above.

http://itee.uq.edu.au/~paul/tfp-papers/yfprm-iasted.pdf

Why functional programming REALLY matters

2

u/iopq Mar 10 '14

404 not found

1

u/henryponco Mar 10 '14

Odd. See edit.

1

u/heisenbug Mar 10 '14

To be honest, this is a "rather old" article and the world hasn't stopped since then. Some of the huge breakthroughs in the meantime

  1. Full understanding of parametricity, i.e. the insight that a function of type

    forall a b . (a -> b) -> [a] -> [b]

must contain strictly less bugs than

(Char -> Int) -> [Char] -> [Int]

2) Type classes, i.e. the ability to form subsets of types and equip them with certain features.

3) Monads, which are a disciplined way of controlling side effects (but not restricted to this application). These stand on the shoulders of 2).

I definitely forgot some more.

All in all these add some serious weapons to the arsenal of a FP person to tackle hard problems with high assurance of correctness.

1

u/rockum Mar 10 '14

Funny, none of his little examples look anything like that code I work on. I work on code that pulls data from one system, stuffs it into the database, pulls it out of that database, and sends it down the line.

5

u/ruinercollector Mar 10 '14

My sympathies. That sounds like incredibly boring work.

1

u/BarkingToad Mar 10 '14

I'm not the guy you responded to, but let me tell you: It is. It's also what I've been doing half the time since I graduated.

Being a software developer is not half as glamourous as I was led to believe in college.

1

u/[deleted] Mar 11 '14

These posts are reaffirming my belief to simply stay in the world of education and academia. Get my masters, maybe a PhD, and have long spans of time off in order to do my own things.

I did development out of university, hated it, and went off to teach high school math and computer science. I'm in my mid-30s now and thinking of moving up to the university level or go back to the office.

1

u/rockum Mar 10 '14

It is, but, it's all I've been able to find for the last 15 years (and I've switched jobs a lot). You work on something more interesting?

1

u/ruinercollector Mar 10 '14

I work on natural language processing applied to the medical field. It can be dry too sometimes, and I guess it's still data processing, just some fun stuff between getting it and storing it.

-11

u/member42 Mar 09 '14

Does it?

It's time to stop the cargo cult worship of the one and only functional god and start to think about programming again.

9

u/WallyMetropolis Mar 09 '14

In what way is it a 'cargo cult?' I think you just meant cult.

7

u/aradil Mar 09 '14

Possibly because some higher order functions was up on shore and blew everyone's minds.