4 ms·
It's always a bit frustrating to read people say that FP doesn't really have design patterns. Most of the OOP design patterns usually don't apply, but there are
by rtpg 10y ago
It's always a bit frustrating to read people say that FP doesn't really have design patterns. Most of the OOP design patterns usually don't apply, but there are definitely design patterns.
The most universal one in functional programming is modelling mutating state. This is solved by placing the state in some container, and then building functions that take a state, and then return an updated state (maybe with a value). You can then build your program by chaining these state modifiers.
So instead of doing
stack = [1, 2, 3]
def pop_stack():
return stack.pop()
final_value = pop_stack()
# stack = [1, 2]
you do
initial_stack = [3]
def pop(s):
return (s[-1], s[:-1])
popped_value, final_stack = pop(initial_stack)
# final_stack = [1, 2]
# initial_stack = [1, 2, 3]
You can then write programs like the following:
def push(s, val):
return ((), s + [val])
def add(s):
x, s1 = pop(s)
y, s2 = pop(s1)
return push(s2, x+y)
This seems sillier in python, but is essential to doing "real work" in immutable languages. Languages like Haskell offer syntactic tools to make the chaining be more natural, in particular.
- tome 10y agoThat's a pattern with a functional nature indeed but it's not "a pattern in an FP language". In a (typed) FP language you don't need it to be a "pattern" because it's just a type. To my mind a "pattern" is a structure you encode into a program where the language you are using doesn't allow you to encode that structure directly using the facilities it provides.
- rtpg 10y agoI disagree with the sentiment that it's just a type. I understand that you don't need much plumbing, but you're still following a pattern that you have used elsewhere when working on these. The beauty is that there's usually exactly one way of doing it (so by definition it is the simplest way). But if you're coming from a language based around mutability and are just in front of an Haskell REPL, I don't think you find this very easily. In my mind patterns are about agreed-upon architectures for dealing with common issues. Another example that comes to mind in typed FP languages are wrapper types to prevent misuse of values (wrapping user input, unwrapping via "escape" calls). When you have a problem, usually you'll have one or two canonical solutions come to mind. Those are the patterns for me. Though given how simple everything usually is, it involves a lot less boilerplate. Choosing the right type is still essential.
- tome 10y agoRight, I don't really disagree with you, I think. It's just that I associate "pattern" with things that are "done by convention". By contrast the state monad is encoded in the language in Haskell rather than just "done by convention". On the other hand, I would say that your state monad in Python is a pattern, because there's no way of expressing the structure of the state monad in Python.