I think the mindset of "functional is better than ...
# thinking-together
j
I think the mindset of "functional is better than imperative" has led to great confusion. If you are approaching this from the point of view of mathematical tractability (which I agree with) then they are simply different mathematical structures. It's like saying "rings are better than groups". There are areas where the sequential, mutational aspects of imperative code are inessential, and using imperative code is inelegant there ... like using too rich a mathematical structure for a proof, rationals where you just need any monoid. The best place for functional code is "pure computation" without "side effects" like concurrency, I/O etc. But even this terminology gives a weird value judgment, "pure" vs "impure". And then you have this quest to "purify" the impure by simulating I/O with monads - this doesn't simplify the proofs at all, the putative goal of the exercise. Conal Elliott did a great job parodying this mindset with "The C language is purely functional".
👍 4
🤔 1
c
Haskell will save us! We must purify the heretics! I never noticed this tone before. A Haskell programmer is walking down the street and steps in gum. He looks down and mutters under his breath with disgust "_mutation!_".
n
I like terms used by Eric Normand: calculations VS actions. Currently I like extreme purism most useful as thinking tool. When I have asked to help with some messy code piles with buggy / unpredictable behviour, I bite the bullet and describe / redesign roughly same system as pure functional style. On that form you can easily spot fundamental errors. After that you can fix them using more or less FPish style. I have couple of wins where nobody else has been able to make sense about the code (even tough code is written completely by themselves) but I can systematically apply this method and solve problem. So this is my current day job superpower 😃 (yea yea no silver bullet I know...)
👍 1
If I would try to do programming language at some point one idea I would like to try is implicit function parameters and returns. First some definitions: Implicit parameters example:
Copy code
f1 = a => a + 1
f2 = a => f1(a) * 2
f2(0) -> 2
Now let's change implementation of f1:
Copy code
f1 = a, b => a + b + 1
f2 wont need to be changed but it now must be called with 2 arguments:
Copy code
f2(0,1) -> 4
Note that this is essentially pretty much the same as (I don't remember the term):
Copy code
f2 = a, b => 
    f1 = c => c + 1
    f1(a,b) * 2
Differences basicly is that f1 is not strictly limited to be used only inside f2. Implicit returns example:
Copy code
f1 = a => (a + 1, 'Called with ' + a)
f2 = a => f1(a) * 2
f2(0) -> (2, 'Called with 0')
So f1 is returning "unhandled data" (kind of log in this case) which is then passed up.
Interesting part: If you just copy paste you Java like code in it's pretty much valid. You are doing imperative logging => it return logs. You are writing to database => return new state/change. You are reading from database => database must be passed as parameter. and so on... And how about if you mix database reads and writes? Should writed states be passed to following reads or should all reads just use same passed database state? Excellent question: raise compile error and let programmer to fine tune parameter flow. If code is tightly called example by UI events and work done in the middle of the events raise another events this flow may not be obvious. It just means that you most probably didn't have any idea what your code would do. Good news is that fundamental problem is now detected and visible. Side note: in F# you may not write any types but inferred types will be still shown to you by IDE. In a sameway implicit parameter passing and return values must be shown by tool suitable way.
Another way to express idea is that side-effects have often dependent from each other and analyzing them functionally could be good tool for that.
Btw I'd like to get feedback as writer if my descriptions are unclear. So if you feel that you didn't understood the point / or it was hard read please react with at least ☝️or something. Be brave 😅
n
@Niko Autio From a skim I did not understand why you believe such a feature would help make programming simpler/easier in any way. You're saying side-effects should just be expressed as implicit parameters? If so, I don't think that would make programs easier to understand. You'd quickly be passing huge messes of parameters around, and your programs would be fragile because they'd break when the compiler can't figure out how to thread everything together.
Some researchers are working on a more principled approach to tagging side-effects in a functional language in the form of "algebraic effects". Yet to be determined how that helps reasoning about side-effects.
n
@Nick Smith Reasoning about side effects is kind of second thought. Primarily it's meant to be able to write side-effect like code while it's actually pure. Idea is motivated by experience I have got when doing purish F#: ~every time you get new random business requirement ("hey when A is X we want completely unrelated B to be Y") you have to refactor part of your application. Kind of "renormalize" it. Somebody might say that this idea make easier to take technical debt which gives you more productivity but indeed if you take too much of... I imagine that outcome could finally be something like that if you have zero tooling it just give somekind of "side effect" ability and if you can live with them in JS you should be able to live with those things too. And in opposite direction where compiler/IDE can visualize parameters well it's just regular pure code only with less writing. So I don't know is this any game changer but I would like to try programming with such thing myself.
However I do believe that on high level future of programming should less write & verify but more like dialogue. So if compiler cannot solve something it's kind of the point. Compiler is there to point out next issue for me.