Usually when authors use the terms "functional programming" and "control flow" together in the same sentence, it's to say functional programming sh...
For further actions, you may consider blocking this person and/or reporting abuse
Great stuff Richard.
And great community input David.
Congrats on the Rubico library also. Keep at 'er.
I notice you have a bunch of posts on dev.to on your functional approach, so over the next little while I'll take a gander through them.
I've only read this post of yours so far, so I'm not commenting on your full body of work, but let me compare with my architectural viewpoint of a functional approach to software architecture.
As far as how things are implemented I care about these attribute, in this order...
More can be said on how those attributes interplay, but the actual implementation that gets chosen is the one that wins out on that prioritized attribute set.
So from your examples above, none of those won out. :)
I'd use the switch statement, as it uses 10 to 20 times less cycles.
After running each func 1e+6 (1 million) times....
Source Code for the timeInLoop func:
gist.github.com/funfunction/91b587...
Hey Richard,
That isPromise check should be fast.
I think your bottleneck there will be the recursion idiom.
The iterative idiom is always faster and more robust.
Any recursion can be replaced with a simple loop.
(I never use recursion, it always fails my robustness and performance tests)
However
However your non-recursive "or" func is slow verses the baseline, and so is its utility, "arrayOr", even when I pass in non-promises (which should make it take the fastest path).
isPromise
Btw, as a little aside, I perf-compared your isPromise implementation with mine.
Now, my isPromise looks more "proper"; and is actually more robust in my robustness test (not shown here), however yours is magnificently faster, by almost 10x :-) ...
prioritized attribute set
So using my "prioritized attribute set" criteria explained in my first post, if I can modify yours enough to be as robust as mine (should be easy to do with very little performance hit) I will swap the slow for the fast.
I think the problem with your code might be that your second "switchCase" is running with a lamba inside of a lamba, so the actual code you want to test does not get hit.
Correct me if I'm wrong.
Here are my results...
It includes the test of the buggy one.
Note:
I ran each "timeInLoop" separately, and about 5 times each, and reported the lowest score.
I looked into it a bit, turns out the differences we were seeing were due to mocha. I was using it to organize the benchmarks, but I see now that I should probably get closer to the ground. I'll also revise rubico's timeInLoop to model yours more closely.
Great.
Keep up the good work, and let me know how it progresses and if you come up with more ideas.
Nice!
Feel free to post the source code and I'll give it a shot myself.
And yes, as I had mentioned in the Tips section of the Post I linked to above, each test must be run separately, otherwise the compiler may optimize some code by learning from the other code.
switchCase benchmarks here: github.com/a-synchronous/rubico/bl...
could you elaborate on natural language documentation?
Hey Richard,
I just posted an article to elaborate on that...
dev.to/functional_js/squeezing-out...
This is very interesting, Richard -- definitely fun exploration.
Your example begins looking very declarative (one of the awesome things about FP), and almost like SQL if one squints.
I've never gone beyond using the native functional facilities in the standard library and I used them quite a bit when I worked with JS, but curious as to whether you're familiar with Lodash's FP module: github.com/lodash/lodash/wiki/FP-G.... It definitely doesn't provide an interface that Rubico provides for handling conditions. I've never dove deep enough into Haskell to know whether what you're doing is an adaptation of an idea there
rubico is very much a JavaScript library, and was born from my own needs as a JavaScript developer. I have tried my best to preserve the good work and idioms of more traditional fp'ers, but rubico did not come from another language or another set of practices. I would say what I'm doing here with control expressions in rubico more borrows from earlier work trying to abstract the query DSL of elasticsearch. That produced something like this
I wanted rubico to be less of a grab bag and focus more on absolutely necessary syntax. You could in some ways consider
hasFlag
as a new member of the syntax available to solve the problem of a command line interface. Also, I've left an option for a "grab bag" of sorts called rubico/x. Basically if you have a function you like (like lodash defaultsDeep), you could add it into rubico as rubico/x/defaultsDeep. Then you could import it likeFP has control flow, but one that is rather determined by arithemtic laws and non-strict evaluation than the lexical position of statements/expressions. An operator can be associative, commutative, distributive. Monoid, for instance, is associative, but not commutative, which gives you a precise and predicable control flow. The entire Monad type class exists to compose statements and thus allow modelling control flows similar to those in imperative programming.
Doesn't control flow imply statements? My understanding is pure functional programming languages do not have statements and control flow is an imperative only construct.
Consider the following computation:
You need an order for that. Another example:
Function application establishes a left associative evaluation order. Function composition establishes a right associative one.
With monads you define evaluation order of function composition with side effects (first example).
Now if you refer to the purely functional theory (lambda calculus) you are almost right: There are different evaluation strategies and the compiler decides which one is applied.
You can even write: Loosely speaking there is no evaluation order in FP, but this is a simplification.
The thing is that if you compare this to simple switch then the winner is not so obvious.
dev.to/macsikora/switch-is-ok-336l