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).
Tacit programming
41–50 of 95 posts
Re: Tacit programming
#42 (defn blackbird [f g] (fn [x y] (f (g x y))))
or (def blackbird (comp comp comp))Re: Tacit programming
#43I really enjoy trying to think through programming problems in a dataflow style like this. It often turns the problem inside out in an interesting way. I did about half of this year's Advent of Code problems in such a system and it was a blast.
Re: Tacit programming
#44Tinkering 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…
Re: Tacit programming
#45Seems 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 thi…
> 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.
In maintenance, you often cannot assume that your functions are good abstractions. One of them is doing something wrong, or at least something that needs changed. Which one? You have to go into the implementation details in order to find where you have to begin to work.
That's not "bad examples" of FP. That's just how software maintenance is. And maintenance is going to happen to FP programs too...
Re: Tacit programming
#46Absolutely 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…
Re: Tacit programming
#47The graphical dataflow languages that are popular for music and audio programming (thinking Pure Data, Max/MSP, Reaktor etc) do this in a way that makes the value of "namelessness" a bit more clear. When you connect the output of one unit to the input of another unit, there's no need to name that linkage, but it's still perfectly clear what's flowing over it. I really enjoy trying to think through programming problem…
Re: Tacit programming
#48The 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'…
The wiki page explains it in the very first sentence: “… in which function definitions do not identify the arguments (or "points") on which they operate”.
Re: Tacit programming
#49I 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…
I'm smiling a bit because I know exactly what you mean and generally agree, with an exception. A common idiom in Elixir is to return {:ok, result} or {:err, :reason} from calls that can fail. Leaning on that idiom, good function names, and good errors goes a long way: params[:id] |> find_user |> verify_user_has_access_to(params[:post_id]) |> etc When I define the functions I'll use pattern matching on the first argum…
Re: Tacit programming
#50The 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…
[0] https://en.wikipedia.org/wiki/Builder_pattern
Both builders and fluent interfaces have little to do with point-free style. X.foo().bar().baz() is not any more point-free than baz(bar(foo(x))).