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.
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 usesplit
).x=x+1
can blow up an unexpecting brain. Functional programming is natural, it is nothing more than pure and convinient strictly mathematical functions.