Live data from Hacker News

Tacit programming

en.wikipedia.org

21–30 of 95 posts

Re: Tacit programming

#21
post #20

The broader idea of “pass a value between functions without naming it in the caller” crops up in a few other places outside FP. In Rust there is the “builder pattern”[0] where the builder isn’t mentioned directly: ByValueBuilder::new() .with_favorite_number(42) .with_favorite_programming_language("Rust") .build() In OO land they are called “fluent interfaces”[1], commonly used when building SQL queries while only men…

The framing of the builder pattern as primarily a Rust feature, and fluent interfaces as primarily an OO feature, is a bit odd.

A prime example of non-builder fluent interfaces are containers in Rust.

Both builders and fluent interfaces exist pretty much in all languages that can support chaining methods on some sort of object. This includes OO languages as well as totally-not-OO languages like Rust that just stop short of calling their classes "classes."

Re: Tacit programming

#22

I love the concept of point-free programming - write your function by simply concatenating the transformations you want. I just hate reading the resulting code written by others. What information is expected to come in, and exactly what data passes from one step to the next, and in what position? Data type signatures only go so far. Point-free means you have all that wiring in your head, without assistance from the n…

Just like there is "decision fatigue" [1] I believe there is "naming fatigue", and naming are one of the three great problems of computing, as everyone knows.

I'd say that at least point-free prevents naming fatigue, but for the result to be nice to the reader, the naming and factorization is much more important than with explicit code, which has sort of much more "safeties".

On the specific question you ask, let's hear the creator of one of the major stack oriented languages, Forth, by its inventor when he had about 30 years of professional practice. He talks about code comments, which is the local solution that comes immediately to mind when thinking about the issues you pointed out:

So people who draw stack diagrams or pictures of things on the stack should immediately realize that they are doing something wrong. Even the little parameter pictures that are so popular. You know if you are defining a word and then you put in a comment showing what the stack effects are and it indicates F and x and y

F ( x - y )

I used to appreciate this back in the days when I let my stacks get too complicated, but no more. We don't need this kind of information. It should be obvious from the source code or be documented somewhere else.

Well, comment-less code isn't popular either, but we're not here to design the next Python anyway. By the way, Chuck Moore evolved his language until he determined that the remaining problems were "in the hardware". He did his own CAD tools with his language to design stack-oriented CPUs with some success, as some of them ended up in spacecrafts (notably Philae in 2014 [3]).

In my experience, when you want to keep the data flow as simple as possible (in Forth: keep "stack juggling" to a minimum), there's very often only one good order for parameters. That works very well for the writer, for whom the understanding of the problem helps with memorizing signatures and semantics. As a reader (of other's code), I have much less experience, but I guess that understanding the same things requires the readers to invest more time up front, in addition to the "accidental obfuscations" (poorly written code, unusual programming habits and conventions...).

[1] https://en.wikipedia.org/wiki/Decision_fatigue [2] https://www.ultratechnology.com/1xforth.htm [3] https://en.wikipedia.org/wiki/RTX2010

Re: Tacit programming

#23
post #9

Absolutely every single time when I use functional programming, I store my intermediary calls in a variable, specifically because naming that variable forces me to explain what that intermediary result should be. If the intermediary result makes no sense, and only the function composition makes sense, I'll create a new well named function that does the chaining, even if it's single use. This is literally the only way…

Yeah, point-free sounds cool, until you actually try it out. Even in their example they are not point-free:

    compose(foo, bar, baz)
Here compose is applied to three "points" (which happen to be functions).

Re: Tacit programming

#24
post #4

Why not translate your code to pointfree style automatically? Using[0], you can go from quad a b c = let d = b * b - 4 * a * c in ((-b + sqrt d) / 2 * a, (-b - sqrt d) / 2 * a) to ghci> import Control.Monad ghci> quad = ap (ap . ((.) .) . ap (ap . (liftM2 (,) .) . flip (flip . ((*) .) . flip flip 2 . ((/) .) . (. sqrt) . (+) . negate)) (flip (flip . ((*) .) . flip flip 2 . ((/) .) . (. sqrt) . (-) . negate))) (flip (…

Clearly superior.

Re: Tacit programming

#25
The first time I've read about tacit programming is in one of the blog posts on oilshell [1].

Really like the idea and apparently one of my favorite features of UNIX is the pipe facility, and it's actually a form of tacit programming. This makes a lot of sense since the OS itself is already full of ready made functions that can be exposed through the API [2].

It's also interesting to note that most of the modern programming languages for examples Python, Ruby, Perl, and JavaScript are missing or have awkward support of this feature.

[1] Pipelines Support Vectorized, Point-Free, and Imperative Style:

https://www.oilshell.org/blog/2017/01/15.html

[2] The Linux Programming Interface:

https://man7.org/tlpi/

Re: Tacit programming

#26
This technique is highly useful in moderation, provided you are working in a language where the syntax/semantics affords it. It can certainly be overdone to the point where the code becomes harder to decipher for a human reader.

A key step is that programming languages which use the style builds a vocabulary of commonly used operations and make these into general knowledge for programmers using the language. Thus, succinctness is obtained and you can compress hundreds of lines into a few. Flip side is a steeper learning curve, which has to be balanced against.

Re: Tacit programming

#27
Tinkering with APL (Dyalog) gave me one of my most mind-bending programming moments.

  dismal ← 10⊥(⌈/10⊥⍣¯1⊢)
This is the complete solution to addition in the framework of Dismal Arithmetic [1].

The pivotal idea there was the inverse of a function, and "trains". Until that moment of insight, I was fiddling about with dfns, which looks janky in comparison.

  dismal ← {10(⊤⍣¯1)⍵}∘{⌈/⍵}∘{10(⊥⍣¯1)⍵}⊢
⍣¯1 is APL for "inverse". Aaron Hsu helped me understand [2] what was going on.

I feel like this kind of conceptual power is tacit programming at is finest. It blows my mind that this alien gobbledygook code still makes sense to me after not touching APL for years now. And I've only toyed around with the language.

[1] I was playing with the problem to compare Clojure and APL, just because. https://www.evalapply.org/posts/dismal-arithmetic-dyalog-apl...

[2] https://www.sacrideo.us/decoding-inverses/

(edit: fix typos, verbiage)

Re: Tacit programming

#28
How is omitting the names in any way beneficial? It all ends up as memory addresses in the end. Surely the important point is the sequential data flow.

I often use point-free style myself (pipelines), but I'd never pretend it's good practice. Pipelines are a quick-and-dirty hack for when you're too lazy to use a better programming paradigm. They're "write only", in that it's quicker to write one from scratch than to understand an existing one.

"Tacit programming" as a concept sounds like typical mathematicians' obscurantism, like their love of single-character variable names and implicit operations.

Re: Tacit programming

#29

Seems like a maintenance nightmare tbh. You have to jump at a billion functions definitions before you can hope to understand what a program is doing. I could see myself transforming a functional program into a procedual one as I try to understand it just so I can have all information just in front of me and not have to keep things in my head. Like I get that a functional style helps with the mathematical correctness…

> You have to jump at a billion functions definitions before you can hope to understand what a program is doing

On the contrary, if you assume that your functions are good abstractions then you shouldn’t need to know their implementation details in order to compose them. You can tell what it does by looking at just what you have in front of you.

If that’s not the case, then you’re not looking at a good example of this concept. And we all know we can find bad examples of any idea or paradigm— what is useful is the good examples.

Re: Tacit programming

#30
The wiki page leaves out the source of the the 'point-free' nomenclature - category theory ( e.g. https://en.wikipedia.org/wiki/Pointless_topology ). The original game was talking about sets (or other similar objects) without talking about 'set membership'/'elements', whence 'point-free'; you want to only talk about functions between sets (or morphisms between objects), and build everything up from those.

Is 'tacit' an old term or a newer rebranding?

(edit: https://en.wikipedia.org/wiki/Whitehead%27s_point-free_geome... might be earlier than the category stuff, but not sure if it used the 'point-free' nomenclature, nor if it has a direct lineage to the later category theory stuff )

Post reply on HN