Functional calisthenics
codurance.com
codurance.com
I remember when OOP came up, some people made functions illegal. So instead of
s = sinx(x)
the OOP way was
m = new Math() s = m.sin(x)
And instead of switch statements you had to derive a new class for each case call a virtual function. Very "OOP" but it led to the OOP equivalent of spaghetti code.
Are the functional guys also starting to leave the real world for the sake of being "pure"?
I wouldn't expect anyone to follow them religiously in production code.
m = new Math() s = m.sin(x)
would be "the OOP way" instead of x.sin
?Besides this nitpick, i concur with Veen. The post seems to be about exercises/challenges, not FP best practices.
Good point. I guess in C++ numbers aren't objects so you can't do this.
I hope they understand that this is just an exercise. I have seen too often these things being elevated into a religion.
Yeap. I have no hard preference between sin(x) or x.sin, in an OOP context or not, as long as the language is somewhat consistent (e.g., it bothers me that Ruby has some of these functions on the numbers themselves, like 1.23.floor, but others live on Math, like Math.sin(42)).
Every time I type `len(some_list)` in Python, I die a little inside.
Because you can't do the latter post-hoc. You can't add hyperbolic functions by yourself if your standard library didn't anticipate them. Well, in Ruby you can and it's a standard practice to pollute this way classes at random, and in Python you can as well, though it's frowned upon, but certainly you cannot in C++ or Java.
These rules are constraints on how to create your code
and are only intended to be applied when doing katas or
exercises.
These rules are an exercise to kick you out of an OOP mindset, not best practices for writing real code.By that same token, I think it is a good rule when practicing OOP to not allow bare functions. It helps train yourself to think "Is there a logical class that this method belongs to?" In real code, of course, the answer is often "no". But when first learning OOP, it's good to teach yourself to ask that question in the first place.
Your code isn't a good example of "the OOP way", though. A fluent OOP solution would be:
s = x.sin()
Another good rule when practicing OOP would be "No classes without state." That helps you avoid the habit of writing pointless "namespace" classes like the "Math" class you define here. Of course, again, sometimes it is useful to wrap a bunch of related behavior in a stateless class, but that should be the exception, not the default.I can not see how they could be used to help escape analysis more than that you have one less reference (this).
Also, to reverse that perspective, a "type" in Erlang/Elixir-lang is just any data formatted in a way that a given set of functions will work with it, rather than requiring an explicit tag. {1, 2} can be an instance of a type†, if you have a module Foo that spits that shape of data in response to Foo.new/0 and takes it for Foo.change/1.
† An example of such a type is Erlang's http://erlang.org/doc/man/queue.html . queue:new/0 just returns {[], []}.
Given
{ a: { b: { c: 4 } }, d: 2 }
return { 'a.b.c': 4, d: 2 }
My go to solution uses mutable state, self-recursion, and intermediate variables: function flatten(source) {
var result = {}
_flatten(source, null, result)
return result
}
where `_flatten(source, prefix, result)` is self-recursive (`prefix` accumulates the keys) and populates `result[prefix]=value` when value is a string. `result` is conceptually an IO monad that's passed along.I guess the general problem would be traverse a tree of arbitrary depth and accumulate structured data on the go. Prominent examples would be compilers.
Any hints on where to start?
I disagree. Switch statements are fine to react to incoming data, but terrible for everything else. If you add a value to an enum you have to change every place where the enum is used in a switch. And the code inside the switch is not reusable (Unless you make it a method, at which point you're close to the "OOP" way anyway). I agree that religiously avoiding switches lead to spaghetti code, but mindlessly using them does so too.
This is easy to write in C, and I always imagined would be something functional programming would excel at, but it doesn't seem to fit with your rules.
The idea is that the only explicit recursion is contained in generic combinators "fold_result" and "unfold_result" that are "boring" in the sense that they can be derived mechanically from the "resultF" data type and do not actually know about the binary search; they just do recursion.
In practice, folds and unfolds tend to be more useful for other things.
Really if you aren't following <Edit> Most <Edit> of these rules you are not doing functional programming.
The best way to learn about functional is not to follow these rules but to use a functional language that basically enforces these rules. Javascript is not a good language to learn about functional programming.