Simple Functional Approach Example

Btw I'll be submitting the final FP write up and solutions this evening. Solutions will be included for the following languages:
  • Python
  • Scala
  • Swift
  • C#
  • Java


Note:
  • Write-up will talk through process for python only, but as you'll see the code is quite similar between languages, so it'll be easy to substitute your preference for each python snippet.
  • I btw didn't bother about Kotlin re nobody submitted code or asked.
 
Ok here's the conclusion to all of this. I've opted to do the write-up in a gist, primarily because it's far easier to format this type of article outside of MyBB. I will however include an extract of the Python solution below:

Link to the solution write up on github gist.

Solution code per language (links to a gist for each language):

Here's an online version of the Python code:
Which btw also includes assert based testing and usage examples.

PHP:
# Functions 
def vowel_pattern(v): return list("aeiou")[v%5]
def zero_or_one_pattern(v): return str(v%2)
def alternation_of(fn, n): return map(fn, range(n, n*2))
def binary_alternation(n): return alternation_of(zero_or_one_pattern, n)
def binary_line(n): return ' '.join(binary_alternation(n))
def binary_triangle(n): return '\n'.join(map(binary_line, range(1, n+1)))
def binary_square(n): return '\n'.join(map(lambda x: binary_line(n), range(1, n+1)))

# Tests 
assert(zero_or_one_pattern(2) == '0')
assert(zero_or_one_pattern(3) == '1')
assert(alternation_of(zero_or_one_pattern, 2) == ['0', '1'])
assert(alternation_of(zero_or_one_pattern, 3) == ['1', '0', '1'])
assert(binary_line(3) == '1 0 1')
assert(binary_line(4) == '0 1 0 1')
assert(binary_triangle(3) == '1\n0 1\n1 0 1')
assert(binary_triangle(4) == '1\n0 1\n1 0 1\n0 1 0 1')

# Output 
print "zero_or_one_pattern(2) ==>", zero_or_one_pattern(2)
print "binary_alternation(3) ==>", binary_alternation(3)
print "binary_line(3) ==>", binary_line(3)
print "binary_triangle(4) ==>\n", binary_triangle(4)
print "binary_triangle(6) ==>\n", binary_triangle(6)
print "binary_square(6) ==>\n", binary_square(6)

Note:
  • Whilst most of the solutions offered in this thread comply with the concept of a pure functions; they are by themselves only a specific solution to a set problem. i.e. not designed for extensibility or composition.
  • As for computation speed; that's going to depend large on the language and it's interpreter / compiler. Still this is function composition, which is generally very fast with little overhead. In Swift this solution in my experience performs faster than it's for loop alternative (Yay LLVM optimiser).
 
Last edited:
[)roi(];21242285 said:
  • Whilst most of the solutions offered in this thread comply with the concept of a pure functions; they are by themselves only a specific solution to a set problem. i.e. not designed for extensibility or composition.

    Link:
    we can hopefully agree that they are all to some degree quite terse and clever in implementation but are hardly something that can be considered very informative about algorithm construction; basically you just have to accept it's correct.

FYI, the reason they are not designed for extensibility or composition or informativeness of algorithm construction is because that wasn't part of the challenge.
 
Last edited:
FYI, the reason they are not designed for extensibility or composition or informativeness of algorithm construction is because that wasn't part of the challenge.
This wasn't intended this to be conflictual;
Still that is how most of these types of programming challenges tend to go anyway. I simply wanted to use this example to demonstrate some of the base technique that typical goes into tackling problems in a more functional way.
 
[)roi(];21237949 said:
Sounds to me like we may be talking at odds-on this one.
...

Yes, sorry, I did not really understand what the wiki page was getting at, so I thought it meant:

Code:
    val buf = scala.collection.mutable.ListBuffer.empty[Int]
    buf.append(1)
    buf append 2  // <- What I thought you meant

In terms of the final solution, those are very nice solutions. However, please keep in mind that many people reject functional programming as overly complex, often after reading articles that give very fancy (purist) solutions to otherwise relatively trivial problems. While breaking a problem down into smaller reusable parts is in general a good thing, one has to watch out for the FP equivalent of the yo-yo anti-pattern. I think some FP practitioners often score own goals when trying to convince more main stream developers to join them, by being too purist in their application of FP, rather than initially going for a comfortable middle ground.
 
Yes, sorry, I did not really understand what the wiki page was getting at, so I thought it meant:

Code:
    val buf = scala.collection.mutable.ListBuffer.empty[Int]
    buf.append(1)
    buf append 2  // <- What I thought you meant

In terms of the final solution, those are very nice solutions. However, please keep in mind that many people reject functional programming as overly complex, often after reading articles that give very fancy (purist) solutions to otherwise relatively trivial problems. While breaking a problem down into smaller reusable parts is in general a good thing, one has to watch out for the FP equivalent of the yo-yo anti-pattern. I think some FP practitioners often score own goals when trying to convince more main stream developers to join them, by being too purist in their application of FP, rather than initially going for a comfortable middle ground.
Glad you liked it.

As with anything, OOP is no exception when it comes to overkill, but that is more programmer than paradigm.

Agree re the functional "purists"; but fortunately there are far less of them in FP circles, everyone I have communicated with over the years is generally friendly and wanting to lose that stigma by making FP more approachable.

Understanding FP naturally takes time and is a gradual process, but that's no different to OOP or anything else; the wins however in the codebase are huge.

For example:
  • Vapor, a web framework solution built in Swift has reported cutting well over 16K lines of code on a 50K project simply by employing parametric based generics and functional techniques. Granted a lot of this was stripping OOP type boilerplate, but that wouldn't have been possible without FP.
  • SAP (the ERP guys), have similarly reported huge cuts occurring in their mobile frameworks since employing these techniques. Their recent commits are reporting e.g. 3.5K lines of code cut on commit and they're still busy with the process.
Bonus that cutting lines of code also means cutting tests.

FP Algebras and axioms (rules) are actually very simple constructions in comparison with design complexity of most OOP design patterns; however the key difference is that whilst FP Design patterns are simple, the complexity is really understanding how how to use them in a codebase. That's they key difference between OOP design patterns and FP design patterns (algebras); OOP patterns are rigidly designed to solve a specific problem, whilst FP patterns are not.

Ps. OOP and FP marry quite well in a codebase; my code ATM is typically more OOP with state and FP overall.

I'll probably share some more base technique in another future thread, to try demonstrate more of this. Will probably be good to link it up with another programming challenge.
 
Last edited:
These threads are awesome
Glad you liked it.
I was certainly happy for all the participation.

Btw. I have another idea in mind that will help to introduce another bit of the base FP algebras (design pattern); again in the form of another computing problem. Similar to this challenge it won't be too complicated (quite easy to solve with standard methods), but I'm hopeful many will be surprised by the versatility of its uses.
 
Top
Sign up to the MyBroadband newsletter
X