13 ms·
Concatenation is composition
- kazinator 4y ago> Compare with lisps applicative version; note the closure does not print readably: Common Lisp has function-lambda-expression for obtaining a function object's source code object, if available, which it may not be: http://clhs.lisp.se/Body/f_fn_lam.htm http://clhs.lisp.se/Body/f_fn_lam.htm Retaining the source code inside a compiled function is a waste of space. Lisps support traditional ahead-of-time compiling. Propagating source code to the compiled binary is not only a waste of storage, but something that some people who don't want, namely those who regard compiling not as only an optimization but as a way of protecting IP and getting paid.
- deleted 4y ago[deleted]
- siraben 4y agoThis approach also extends to embedding languages with different disciplines in a faithful way. With Haskell's rich system you can embed a concatenative, effectful DSL using regular functions[0]. [0] https://gist.github.com/siraben/03510d1bf4d73b6958655887bee69bfe https://gist.github.com/siraben/03510d1bf4d73b6958655887bee6...
- jph00 4y agoThe approach of avoiding having to explicitly name variables is known in computer science as "point free" or "tacit" programming, and in math as "combinatory logic". Languages like APL have even less boilerplate/ceremony for this than shown in the post. E.g the examples shown: [ even? ] [ even? not ] [ 4 > ] in APL are: 2∘| 1-2∘| >∘4 `∘` is partial/bind, and `|` is modulo. Many other languages are pretty good for point-free programming. For instance this series goes into the benefits of using this approach in Swift: https://www.pointfree.co/ https://www.pointfree.co/ Point-free programming has always been a controversial subject. Some people passionately hate it (particularly people that haven't invested in learning to use it) and some passionately love it.
- Akronymus 4y agoAPL is such an interesting language. VERY concise, makes sense but is still incomprehensible to me, without being an actual esolang.
- skruger 4y agoI’ve written a gentle intro to APL for experienced programmers if you’re interested in making it a bit less incomprehensible: https://xpqz.github.io/learnapl https://xpqz.github.io/learnapl
- Akronymus 4y ago> …but it’s unreadable! Should I feel called out? (Yeah, I get that its down to familiarity, rather than actually being hard to read) Interesting read though.
- TuringTest 4y agoFor people without a functional language background, it makes sense to think of point-free style with an example they understand: Unix pipes. The controlled producer-consumer flow in pipes is a subset of the declarative combinatorics of values in a point-free function composition. Approaching it as an ongoing process that generates values and consumes them at the same pace can make it easier to understand.
- Tainnor 4y ago> Point-free programming has always been a controversial subject. Some people passionately hate it (particularly people that haven't invested in learning to use it) and some passionately love it. And for other people, such as myself, it depends on the particular case. I think that point-free style can be clearer and more concise in certain cases (particularly when you're chaining a sequence of operations), but you can also really overdo it. I think when you start to use (in Haskell) "flip", "uncurry", etc., the question is whether it wouldn't be more readable to just name the arguments instead. But obviously, people are going to have varying levels of tolerance for such things.
- tromp 4y agoThe given Haskell example doesn't support their claim that > This is shorter than the equivalent in an applicative language, because we have to name the input argument, that is only used once. It's also wrong in that the predicate (4 >) is equivalent to (\x -> 4 > x) and thus tests for numbers being less than 4. It's strange to argue that concatenation is structurally simpler than application, when you then need to add a quoting operator to add back the needed structure, while introducing a subtle distinction between evaluated and unevaluated code.
- voxl 4y agoBut there is a strong benefit to adding quotation: higher-order programming becomes explicit, and you can restrict it to prevent the need for garbage collectors. "Linear-style" programming becomes obvious to implement in a point-free style, but obtuse when you have variables, adding arbitrary usage restrictions.
- yakubin 4y ago> The given Haskell example doesn't support their claim that >> This is shorter than the equivalent in an applicative language, because we have to name the input argument, that is only used once.* Are you saying that in your eyes the Common Lisp and Haskell snippets are equally terse? To me the Haskell snippet looks a lot shorter and easier to read. Counting tokens also supports that judgement.
- dreamcompiler 4y agoThe Common Lisp example is a tiny bit disingenuous. Common Lisp programmers rarely write (function evenp) but instead write the shorthand version #'evenp
- Jtsummers 4y agoAlso, Common Lisp has a complement function which produces a new Boolean function with the negation of the result: (complement #'evenp) vs the example: (lambda (n) (not (evenp n))) Not much shorter by character count, but it is shorter by token count. http://clhs.lisp.se/Body/f_comple.htm http://clhs.lisp.se/Body/f_comple.htm
- pyinstallwoes 4y agoShout out to https://factorcode.org/ https://factorcode.org/ and nod to Forth
- viraptor 4y agoSpot a person who's been doing very functional programming for too long: > These two fundamental operations -- curry and compose -- have very simple and intuitive semantics.
- nine_k 4y agoThey are indeed simple and intuitive. You can explain them in terms of cooking. Curry: f(x, y) = f(x)(y) For cookies, whip butter with sugar. Curried version: whip /f/ the butter /x/, then whip the result while adding sugar /y/. Composition: f ⭘ g = f(g(x)) To produce nicely shaped cookies, shape the cookies /x/ on a tray first /g/, then bake them /f/.
- chriswarbo 4y agoI don't find these analogies compelling at all: > whip /f/ the butter /x/, then whip the result while adding sugar /y/ That's not a valid explanation, since curried functions don't "act" until they've got all their arguments; i.e. we do not whip any butter until the sugar has been added. > shape the cookies /x/ on a tray first /g/, then bake them /f/ Whilst this is accurrate, I think introducing a notion of time ("then") makes things much harder than they need to be. (That's one reason I find imperative programs hard to understand)
- tantalor 4y agoThe fact that you originally swapped /f/ and /g/ in your comment then edited it to fix there mistake is perfect example of why this is a dangerous and bug prone approach to writing programs.
- mjburgess 4y agoStrange take -- the whole basis of FP is dangerous and bug-prone? Unlike the imperative `;`, which sequences commands in an absolutely obvious way, right?
- nine_k 4y agoIt's just f and g being poor names, also on keys next to each other. The circle is a good symbol for a whiteboard, but it's a poor identifier. Normally you write composition like readFile().then(stripComments).then(sort).then(takeFirst), or compose using shell pipes. Composition is so widespread and so trivial-looking that it's even easy to miss.
- dimitar 4y agoClojure has built-in macros and functions that allow you to do similar composition - without having to name arguments. One of them is to use the threading macros (-> value fun1 fun2), and another one is to use the comp function. Both will require you to name arguments for anonymous functions, but this is likely not an issue as you have even better ways to get a lambda like using partial, comp itself or other higher level functions.