6 ms·
I'll take it one step further. Don't just write pure functions. Write point free combinators. Have you guys ever wondered why no matter how much care or plann
by Geminidog 6y ago
I'll take it one step further.
Don't just write pure functions. Write point free combinators.
Have you guys ever wondered why no matter how much care or planning you use to organize your code when you begin a project, some time down the line you will always encounter a situation where the organizational scheme you chose is less than ideal or even flat out wrong? It's a sort of inevitable technical debt that occurs.
The industry spends an endless amount of time debating and coming up with all kinds of solutions to deal with the above problem. First it was OOP, the latest is microservices.
The actual solution to the above problem is to use point free combinators as much as possible in your code.
- carapace 6y agoI've been playing with Joy (concatinative, combinator-based) and I have to agree. So far everything I've translated into Joy has been more elegant and easier to understand. Conal Elliott's "Compiling to categories" is one way in: http://conal.net/papers/compiling-to-categories/ http://conal.net/papers/compiling-to-categories/
- redisman 6y agoAny paradigm can look clean when you’re playing. Work on it for a year and then have management tell you that we must add a feature that breaks your core design because our big client needs it.
- Geminidog 6y agoMany aspects of a programming language can make it nasty or hard to use under certain contexts. This is something most programmers are aware of through experience. My point is, that the use of combinators and point free programming formally eliminates organizational technical debt. So for this specific issue, Joy should indeed be better by logic.
- AnimalMuppet 6y ago> My point is, that the use of combinators and point free programming formally eliminates organizational technical debt. Hardly. It may eliminate certain kinds of technical debt. Pretty sure it won't eliminate all of it. As you said in a parallel post: > Readability is definitely worse when using this method. Well, that's a kind of technical debt.
- Geminidog 6y agoRead my post: I said "organizational technical debt" to specify debt that has to do with how you organized your logic.
- AnimalMuppet 6y agoBTW, the term "organizational" usually refers to how you organize your people. Even under your definition, though, point-free only helps with a limited definition of "how you organize your logic". How do you organize it into layers? How do you organize it into files? How do you organize it into processes? How do you organize it across machines? You can get real "organizational technical debt" on all of those.
- Geminidog 6y ago> BTW, the term "organizational" usually refers to how you organize your people. Then what, in your opinion, is a better adjective for "technical debt" that best conveys my point? >How do you organize it into layers? How do you organize it into files? Namespacing, files, and "layers" are aesthetic forms of organization that do not produce actual barriers in organization. They are for people to read and do not produce actual structured barriers. Namespace MathLayer1 { function mathlayer1combinator() } Namespace OtherLayer2 { function otherlayer2combinator() } You will note because both functions are combinators, they can always be moved/called interchangeably into either namespace/file/layer provided that you handle circular dependencies (easily done in C++ by declaring everything in a header file first and making sure you don't have any sort of circular recursion in the definitions). Thus "organizational" mistakes in namespacing/layers are actually trivial because none of the combinators in the namespace are tied to context. If you find you can't move a function out of a namespace it is always because of the fact that that function is not a combinator and is likely relying on some other state declared within the namespace/class. It is not the namespace itself that is causing this issue. Another way to think about a namespace or layer is that all it does is put a prefix on your combinator for readability purposes. Layer3.combinatorG as opposed to just combinatorG A third perspective is to view the combinator as a concept that transcends namespacing or layers. A combinator is never limited by scope because it carries the scope with it rather then existing as an entity tied to scope. Machine organization is a problem though. Machines are a physical limitation placed upon our virtual code and people exploiting this limitation as a feature makes code even less modular. A machine barrier is no different from a namespace or object with one difference: Moving or reusing code in a different machine requires data transfer. There is no reason to impose this limitation on our code unless we have no choice. Thus the limitations of machines should only be utilized to optimize for performance, not as a feature to organize your code. Inevitably in practice this can cause organizational debt if you placed a function in machine A for optimization reasons and suddenly find that you need to use that function in machine B things will be inconvenient. Hopefully, if that function is a combinator, moving it for use in machine B will be less of a pain. But keep in mind in the idealistic world of programming the machine barrier doesn't exist. Formally moving your combinator out of Machine B into Machine A is the same as if the Machine was called a Namespace. There is no intrinsic difference. It is the physical limitations of the real world that is making things inconvenient so my statement about combinators still holds logically. That being said the physical barrier of machines can be abstracted away in a single project directory. There are strategies to handle this (imperfectly), docker or RPCs for example. It's Good to have awareness of the exact formal and logical consequences of certain actions rather then rely on some fuzzy intuition of design. Clarity in the fundamentals of what's going on is key to developing a logical rule set so that optimal structure can be calculated rather then sub-optimally designed from intuition.
- carapace 6y agoKind of a pointless objection. Any car is slow if it hits a wall?
- unityByFreedom 6y agoCan 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.
- shakow 6y agoIME, the limitations of this recommendation appear when one needs to combine multiple functions taking multiple arguments, some being fixe and some other not. Although they are mostly syntactic, they hamper the readability of the resulting code.
- Geminidog 6y agoI agree with you. Readability is definitely worse when using this method. It doesn't mean it can't be circumvented with good naming. Overall though this method basically solves the problem with technical debt I described above. The root of all dependencies come from free variables. So if you get rid of free variables and turn your functions into combinators, then all your logic is modular. If you get rid of all variables then all your code has to be combinators. Perhaps the point free style goes to far in terms of readability. Maybe just switching to combinators is a good middle ground. In layman's terms for the readers who don't understand this means don't even use pure functions in classes. Just use functions.
- unityByFreedom 6y ago> this means don't even use pure functions in classes. Just use functions. ... so you agree with the author of this post? Also, seems like there is tech debt with point free, you just have it up front rather than putting it off until later.
- Geminidog 6y agoDepends on the definition of tech debt. Do you mean structural/organizational or readability? If you mean readability then yes, the point free style does not protect you from that imo. But combinators and the point free style does protect you from structural and organizational issues, which is the type of technical debt I'm referring too.
- unityByFreedom 6y agoI meant up front you'd need to write more functions than you would when using functions that allow multiple arguments.
- yowlingcat 6y ago> some time down the line you will always encounter a situation where the organizational scheme you chose is less than ideal or even flat out wrong? I'm with you here... > The actual solution to the above problem is to use point free combinators as much as possible in your code. You lost me here. Perhaps if you're working in a problem space with high complexity, little ambiguity and hard performance requirements (fairly rare in my experience), you might get mileage here. Otherwise, functional programming techniques are somewhat orthogonal to Conway's law. Point-free combinators don't stop new information about customers from completely altering your domain model, business logic and how your data is stored at rest. I think it's helpful to realize that some of the root causes of bit-rot in a codebase are more closely tied to not fully knowing what was going to evolve into ahead of time, which in and of itself isn't a bad thing. However, it means that it's a failure mode that is independent and often out of the hands of the engineer writing the code -- functional programming idioms or not.
- Geminidog 6y agoI'm more referring to a type of technical debt. Of course if your product manager wants you to refactor your web app into a PS5 video game nothing can save you. I wouldn't call the fact that your code wasn't prepared to be refactored into a PS5 video game "technical debt." As most software engineers know, there's tons of examples where the main issue was mostly organizational issues preventing the programmer from simply removing/replacing/moving logic to fulfill the main objective. This is the "technical debt" I'm talking about. In that case if all your logic was combinators (and thus dependency free) then all you need to do is move things around, pull things out and/or put things in like lego blocks. The main reason why people can't move code around like lego blocks is because most logic contains dependencies or is tied to state. Combinators are never tied to state or anything and thus if all your code was made up of combinators you would have no issues in moving logic around. The problem of organizational technical debt is solved with combinators. If you take it a step further and use the point free style, you are eliminating state all together further protecting your program from ever being dependent on state. The logic is pretty sound though most people can't put the benefits of FP into purely logical terms. They only talk about why they like it qualitatively without ever pinpointing why it's truly better for design/organizational issues.
- basicneo 6y agoAny justification for that? IME, the point free style is aesthetic.
- Geminidog 6y agoYes by eliminating state you eliminate the possibility for a function to depend on state. When a function does not depend on state or anything it can be moved, reused and reorganized anywhere thus eliminating technical debt that comes from organizational issues. In other words, all functions in the point free style must be combinators because the point free style eliminates state as much as possible. It's a forcing function to make your logic all combinators and not dependent on free variables. Though I do agree with one replier. It does harm readability so now I'm thinking it may not be the best recommendation. Using combinators without the point free style is enough to actually fix the technical debt I'm talking about.
- asalahli 6y agoIsn't it ironic to complain about the industry coming up with different solutions for the problem, then to suggest the actual solution is X (whatever x is)?
- Geminidog 6y agoWell that would be assuming I’m from the industry. What if I’m currently in some place outside of the industry? What if I have a lot of experience both in industry and outside of the industry? Would it still be ironic? I think the bigger question is what is X and is it definitively correct? Because the irony of a situation has nothing to do with how correct X is.
- amw-zero 6y agoThat doesn’t solve any problem that I have (or anyone has) encountered.
- Geminidog 6y agoYou’re completely right. I’m talking about Technical debt arising from organizational flaws and issues and your statement made me realize this concept doesn’t exist. Nobody has ever dealt with this form of technical debt ever in the history of existence. You’re right, everything I said is completely wrong. I’m not a biased person so I admit when I’m wrong. Also note that this post is not sarcastic. I am 100% serious and being honest here. You are completely right. This is not a joke. It’s rare for people to do a 180 flip so I can see how this post can come off as sarcasm. I am not most people and this post is earnest.
- amw-zero 6y agoI was talking about your proposed solution, not the problem itself. Point free code does not inherently solve any problems, and it certainly doesn't solve the entire notion of technical debt.
- Geminidog 6y agoI could say the same for your statement. It doesn't solve any problems. You stated a point and you need to prove your point. I could just say everything you say is completely and utterly wrong and leave it at that.