5 ms·
Can you describe that in simpler terms? I read the wiki and the Python example seems to suggest writing functions that take a single argument.
by unityByFreedom 6y ago
Can you describe that in simpler terms?
I read the wiki and the Python example seems to suggest writing functions that take a single argument.
- rajangdavis 6y agoI could be wrong, but I take it to mean that the function shouldn't necessarily depend on the arguments that are passed in. Rather, you focus on a set of procedures that are independent of the number of arguments and can act on them. I think it's similar to the concept of Variadic functions(https://en.wikipedia.org/wiki/Variadic_function https://en.wikipedia.org/wiki/Variadic_function)
- dr_kiszonka 6y agoYes, and you can later do fun things with these functions, it seems: https://markshroyer.com/docs/pointfree/latest/overview.html https://markshroyer.com/docs/pointfree/latest/overview.html
- Geminidog 6y agoIt's pretty simple. x = 1 addSomething(y) = y + x The above is not a combinator. addSomething relies on the line x = 1 and is forever tied to it. You cannot reuse addSoemthing without moving x = 1 with it. Therefore addSomething is not modular. This is the root of organizational technical debt. When logic depends on external factors it cannot be reorganized or moved. This is also a big argument against OOP because OOP is basically the same exact thing with a bit of scope around it: class B() x = 1 addSomething(y) = y + x divideSomething ... b = 3 Now addSomething can never be used without taking x=1 and everything inside B with it. It is less modular as a result. A combinator is like this: addSomething(x,y) = x + y fully modular and not tied to state. The point free style is a bit long to explain. Another poster brought up readability and now I think I went too far with it as a recommendation, it's like going vegan basically if you employ that style. Just stick to combinators and you get 99% of the same benefits. Suffice to say the point free style eliminates the usage of all variables in your code. You are building just pipelines of pure logic without any state. When you get rid of state as much as possible, your logic will not have any dependencies on state, and thus will generally be free of technical debt caused by logic being tied to dependencies.
- eyelidlessness 6y agoSo basically, use functions but limit your use of closures? As in define your functions to be dependent only on parameters and not surrounding scope (even if the surrounding scope is immutable/pure)? If that’s the lesson, I’m all for it, with the exception of fully local closures that are used more for expressiveness than standalone functionality.
- Geminidog 6y ago>So basically, use functions but limit your use of closures? Not limit, terminate the use all together along with classes because methods in classes are basically closures. >I’m all for it, with the exception of fully local closures that are used more for expressiveness than standalone functionality. Sure I can agree with this... formally though. When you write a local closure you are preventing it from ever being reused. The philosophy of this style is to assume an unknown future where anything has the possibility of being reused. When too much of your logic gets inserted into "local closures" your program will be more likely to hit the type of organizational technical debt I am talking about above. It's not a huge deal breaker though, you can always duplicate your code to deal with it. I'm not against shortcuts but most programmers need to know when they are actually taking a shortcut while being aware of the formal rules that will actually eliminate organizational technical debt. Many functional programmers are unaware of the the origins of organizational technical debt and mistakenly build technical debt into their programs with closures even when it wasn't their intention which is separate from your case as you are doing it intentionally.
- eyelidlessness 6y agoI think we’re mostly in agreement. I’m a little looser than your absolute in practice, but I apply the same principles. Where I’m looser is basically an allowance for closures as a simple expression (and where languages with more expressiveness may not require a closure). If any local logic becomes more complex than that, I’m quick to parameterize it and move it out to its own function.
- ellis-bell 6y ago
- felixyz 6y agoThis talk is an excellent, very accessible introduction to point free style and some of its tradeoffs: "Point-Free or Die: Tacit Programming in Haskell and Beyond" by Amar Shah https://www.youtube.com/watch?v=seVSlKazsNk https://www.youtube.com/watch?v=seVSlKazsNk
- kubanczyk 6y agoThe title is a bit clickbaity, the "or Die" is not really addressed in the actual talk. But the hilarity... I would rename that video to "Tacit Programming: It's Not A Joke <everyone bursts into laughter>"
- kubanczyk 6y agoI think the easiest way to explain point-free is this bash snippet: grok () { grep -v DEBUG | sort -n | uniq | tail } Unlike a generic pure function, it forcibly abstracts away arguments. It's a bunch of other functions combined somehow, but it's impossible to know the type/structure/semantics of the input. And in most cases also of the output! Although it's less visible in my example.
- Geminidog 6y agoOf course it’s possible. Just look at the type signature of each function to know what goes in and what comes out. Not much different then looking at the type signature of an assigned variable. Debugging the point free style is different though as there are no points to put your breakpoint. Think of the identity function with a side effect as a replacement for print or breakpoints.