12

Is functional programming just different, or is it actually really tougher?

Say someone who have never learned programming at all before, and is taught functional programming. vs someone who have never learned programming at all before, and is taught imperative programming. which will he find tougher? or the same?

My question: say the problem now is to camel-case an input,

such that qwe_asd_zxc_rty_fgh_vbn becomes qweAsdZxcRtyFghVbn

The procedural way is:

  1. split it along the _
  2. loop through the array skipping the first item
  3. for each entry we capitalise the first letter
  4. join the results together

The functional way is:

  1. if cannot find _ return input
  2. cut the input along the first _ (such that we get qwe and asd_zxc_rty_gfh_cvb)
  3. capitalise the first letter of head and concat that with f(tail)

Ok if you have a functional-background AND have substantial experience in procedural-programming, I would like to ask: will it take you longer to figure out the procedural way or will it take longer for you to figure out the functional way?

If you have a procedural-background but have many years of experience with functional-programming, I would like to ask the same question: will it take you longer to figure out the procedural way or will it take longer for you to figure out the functional way?

5
  • 5
    Ehrm, the "procedural way" seems perfectly functional to me if we use map for step 3 instead of a mutating loop. The second approach is something I'd only consider if there is no split function in the standard library (in which case it should be compared to an imperative solution which also does not use split).
    – sepp2k
    Commented Jun 10, 2011 at 4:58
  • 9
    There's nothing specifically functional or procedural about either of your examples. It sounds to me like you're trying to extrapolate from a faulty understanding of functional programming. No wonder you're getting unusual results. Commented Jun 10, 2011 at 5:12
  • I don't think that functional programming is tough, it's just different. If you have no programming experience either are just as easy to learn, but for some reason once you learn imperative programming, functional programming becomes difficult. Commented Jun 10, 2011 at 5:17
  • 1
    I think the distinction between functional and procedural becomes moot, since maintstream languages like JavaScript, C#, Groovy contain more and more functional features.
    – user281377
    Commented Jun 10, 2011 at 7:59
  • 2
    Imperative programming is much more difficult and counter-intuitive for those who had no previous programming experience. An expression like x=x+1 can blow up an unexpecting brain. Functional programming is natural, it is nothing more than pure and convinient strictly mathematical functions.
    – SK-logic
    Commented Jun 10, 2011 at 10:35

5 Answers 5

12

Just different. Functional programming is much more closely related to mathematics, which most people are familiar with. The whole "immutable variables" thing only comes a shock to imperative programmers where the "mutable" mindset is deeply ingrained.

To newcomers, it is often fairly intuitive that you can't just change the value of something.

Where I studied CS, we were taught a functional language as our very first course. And everyone who'd learned C++ or Java previously struggled with it. Those who were new to programming picked it up fairly easily.

4
  • jalf are you one of those new to programming and picked it up fairly easily?
    – Pacerier
    Commented Jun 10, 2011 at 9:36
  • I was somewhere in between. I'd poked around a little bit with C++ and some PHP before then, but not enough to really get used to the imperative mindset. The pattern was pretty clear when you looked at the class as a whole. Also, this was nearly a decade ago, so no, I'm not quite new to programming today ;)
    – jalf
    Commented Jun 10, 2011 at 10:05
  • Immutable variables? Isn't mathematica a functional programming language? variables in mathematica are surely mutable, no?
    – user56834
    Commented Jan 18, 2018 at 18:21
  • Is it possible that in this introductory course you were purposefully given assignments that are a good fit for functional programming? Talking about math, it seems to me that efficient implementations of non-trivial graph algorithms would not be very easy with functional programming (although I'd love to be proven wrong, and yes I know that certain algorithms, such as connected components, are straightforward). Or let's take physics, implement an Ising model simulation with Glauber dynamics, a good example of a common type of physical simulation ...
    – Szabolcs
    Commented Dec 1, 2022 at 20:20
21

It's just different

When you program you essentially translate the way you reason into code, the distance between your thoughts and the final solution might be said to be the "cognitive gap". The bigger the gap the harder it'll be for you to bridge it.

If you come from a procedural background you will have trained yourself to think procedurally so the gap will be less then for functional code, and vice versa.

The only way for a programming paradigm to be intrinsically easier than anything else would be if it mapped to something you already knew, like ordinary language, so you'd start off with a shorter gap.

Functional and procedural is a pretty fluid concept anyways and they tend to overlap

4

Yes, functional programming tends to be difficult for many people to comprehend (I'd tend to say, especially those who've already been exposed to procedural programming first).

I'd also say your example of functional programming isn't really a very good example of functional programming though. It's using recursion and just composing a result instead of modifying state, but not much more than that.

To get a better example of functional programming, consider a more general problem: rather than "search for an underscore and convert the next letter to uppercase", consider this as just one special case of searching for a pattern, and executing some arbitrary code when it's found.

A lot of languages support that, but to do so they require that we specify the pattern as something like a regular expression. Regular expressions, however, are nothing more or less than a special-purpose programming language, and an RE implementation is a compiler and/or interpreter for that language. The result of compiling the RE is basically a function that executes (in a special RE virtual machine) to match the expression against some input.

In something like Perl, you use a special language to specify the pattern, and a special compiler to convert that string to some sort of function-like thing, and a special interpreter to take that function-like thing an execute it. In a functional language, you'd typically use the language itself to specify the pattern, and use the language's own compiler to produce a real function. We can generate that function on the fly (about like we can compile an RE when we want), but when we do, the result can execute like any other function in the language instead of needing special RE stuff to do it.

The result is that we can generalize the problem above relatively easily. Instead of hard-coding the '_' and "upper-case" directly into the transformation, however, we can have something like:

s&r(pattern, transform, string) {
    if (!pattern(string))
        return string
    else
        return transform(matched part of string) + s&r(rest of string);
}

But, unlike something where we specify the pattern as an RE, we can specify the pattern directly as a real function, and still use it, something like:

my_pattern(string) return beginning(string) == '_';

And then we pass that function to the s&r. Right now, it's a pretty trivial function, and we've encoded it entirely statically. A functional language largely becomes interesting when we use it like we can REs, and generate an entirely new function on the fly based on something like user input, but unlike an RE that function doesn't need a special RE interpreter to run -- it's just a normal function like any other.

4

Here's the complete code in Racket:

;; camelize : string -> string
(define (camelize str)
  (let ([parts (regexp-split #rx"_" str)])
    ;; result of regexp-split is never empty
    (apply string-append
           (first parts)
           (map string-titlecase (rest parts)))))

(camelize "qwe_asd_zxc_rty_fgh_vbn")
;; => "qweAsdZxcRtyFghVbn"

As a functional programmer with procedural experience, I don't think it would take me longer to "figure out" a procedural solution, but it would certainly take me longer to type it.

BTW, the example expected result in the original post is wrong: it's missing an "h" near the end.

1
  • gd for pointing that out. edited
    – Pacerier
    Commented Jun 10, 2011 at 8:02
3

My pet theory is that programming models are easier to understand the closer they are to the actual working of computers. Pointers are hard to understand until you realize that they are essentially machine addresses. Recursion is hard to understand until you have consciously stepped through a small example, seen the stack frames, and realized where the different values of the same variable are stored. That doesn't mean that assembler programming is easier than high-level programming, but having seen how it's done does wonders for the mental model that is key to proficiency - whether in programming or in general usability.

Now, the procedural model is somewhat closer to the usual machine architecture: assignments are memory (or register) writes. Procedure calls are really just fancy jumps, an if is actually a conditional jump, etc. But in Lisp, for example, there is no simple low-level equivalent to a lexical binding or a lambda expression. Understanding it requires you to imagine a completely separate abstract functional machine between the language level and the physical machine, because and apparently most people never get that far.

(I am familiar with the idea that the von Neumann architecture is ultimately arbitrary, and we shouldn't prejudice beginner's minds with such irrelevant details of machine architecture, and instead directly introduce them to the semantics of programming languages. In fact, I've taught a few such courses myself. But increasingly I feel that this a noble but misguided goal; people learn programming by building understanding from the bottom up, and the way to functional programming is simply a bit longer.)

4
  • 7
    By that logic Assembler should be the easiest of all languages to learn :)
    – Homde
    Commented Jun 10, 2011 at 7:19
  • 4
    Functional programming is quite easy to understand if you come at it from the right direction. The "abstract functional machine" you mention is simply algebra. Evaluation is done by term rewriting; function application is done by substitution. Programmers learn to solve problems using the same tools they've already seen in years of math clases. If they pursue CS, there's time enough to meet the stack of turtles later; if not, they've still learned useful problem-solving skills and design principles. Take a look at How to Design Programs. Commented Jun 10, 2011 at 7:40
  • 2
    @mko No, by this logic the actual bytecodes 011011001001101... would be the easiest language to learn!
    – MarkJ
    Commented Jun 10, 2011 at 12:09
  • 2
    @konrad: RISC assembler IS probably the easiest language to learn. To know how to make it do something useful is another story all-together...
    – Bryan B
    Commented Jan 25, 2012 at 20:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.