As someone who is just starting to learn functional programming, do you believe this is because "we've" all been taught to think imperatively, and functional is just new to us? Or is it something inherent in functional style coding?
As someone who is just starting to learn functional programming, do you believe this is because "we've" all been taught to think imperatively, and functional is just new to us? Or is it something inherent in functional style coding?
(Sometimes I get in trouble when I try to distinguish between "new functional" and "old functional", but despite superficial similarities they are diametrically philosophically opposed. Old functional, embodied by Lisp, works by trying to empower the programmer, and builds on that; new functional works by restricting the programmer and building on what guarantees we get from those restrictions. Haskell and Lisp may share some terminology when it comes to list manipulation but I would actually put them very, very far apart in my grand map of programming languages; they take one step together, the first lambda calculus step, and then immediately begin sprinting in opposite directions.)
I'm also not sure I'd go as far as to say "restricts" as much as demarcates. Composing existing code has been vary difficult in imperative languages (practically impossible when you have to deal with things like memory management and/or threading).
If you have a system where 95% of it is functional, cool, you've eliminated 95% of the places where you have to double-check for dataflow/mutability-related bugs. (To heavily paraphrase jerf's comment: functional programming is about accepting restrictions that make debugging simpler.) Make the system as clean as feasible, but don't get bent out of shape trying to get the last 5% FP-approved. It's probably less trouble to just know that's the hairy part.
The big idea in functional programming is that working with immutable data structures makes a lot of annoying bugs go away, and goddamnit, they're right. Does that mean you need to go 100% immutable? No - it's just a good default.
FP-style programming without (generational) garbage collection is really awkward, though - immutability means you're going to be creating a lot of temporary data structures. Good language implementations will recognize this and just stack-allocate them or let them go in the first collection.
With Haskell, you know that something that claims to be pure is.
Haskell is unusually strict in that regard, turning what is normally a design option into an all-or-nothing situation.
Edit: I know there are a few ways around it via monads, but the culture surrounding Haskell seems quite a bit more likely to treat state/purity as an all-or-nothing issue than the others'. Maybe I'm making inaccurate assumptions about Haskell based on the loudest members of its community, though.
(There is also the good-old-IORef, but I avoid IO for anything that's not input or output.)
Doubtless others will disagree though. Maybe we don't all have the same mental strengths and weaknesses.
Recursive cases in languages with tail-call optimization are like inductive reasoning in mathematics - "How long is a list? If it's empty, zero, otherwise one (for the head) plus however long the rest is."
At least in some cases, I think that's the expected result: consider the difficulty of reversing a singly linked list in-place and reversing it applicatively.
There is stuff to learn in every language :)
(Node: I don't no haskell)