Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function composition operator #258

Open
LeaVerou opened this issue Aug 6, 2017 · 6 comments
Open

Function composition operator #258

LeaVerou opened this issue Aug 6, 2017 · 6 comments

Comments

@LeaVerou
Copy link
Member

LeaVerou commented Aug 6, 2017

Currently, expressions can require a lot of nested parentheses, which is something even seasoned programmers often err on 1. One way to solve it would be to try to perform fixup and add forgotten parens or remove extra parens if expression evaluation fails (is this a good idea?).

Another way would be to design the syntax in such a way that unnecessary parens are eliminated. A lot of the time, the output of one function is the input of another, with no extra arguments. We could introduce a function composition operator that eliminates parentheses from such function calls, like to the one in Maths where g∘f(x) = g(f(x)).
For example, with such an operator, an expression like readable(to(filename(image), '.')) would become readable ∘ to(filename(image), '.').

Obviously, we can’t use ∘ for the actual operator, since that would be a pain to type. We could use the actual word of, which is how such function calls are often read anyway. The example would then read readable of to(filename(image), '.'), which is not terribly readable (oh the irony), but is not too bad. Most importantly, it seems to really improve things in terms of parens: even by removing 1 pair of nested parens, it became much easier to balance them.
Alternatively, it could be a non-word operator, e.g. <<. The example would then become readable << to(filename(image), '.').

Thoughts?

@karger
Copy link
Collaborator

karger commented Aug 8, 2017 via email

@LeaVerou
Copy link
Member Author

LeaVerou commented Aug 9, 2017

Good ideas re: inverse order and pipe! Yet another reason for this operator: that order is much more natural. A bit concerned that pipe might be confused with OR by those that have used JS.

Now that the order would be reversed, what about then as the operator? That would read quite naturally! I quite like words as operators.

The operator could also work by currying, where x | a | b(5) would be equivalent to b(5, a(x)) or b(a(x), 5). That gives it more power without complicating simple usage.

On the other hand if they've done a lot of math they'll expect the opposite; a conundrum.

No conundrum, I think we can safely say that the population that has done a lot of maths is comparatively fairly small :P

But I do wonder whether this kind of chaining of functions is good for
non-programmers, or if they might be better off defining a sequence of
intermediate variables/properties a=f(x), b=g(a), c=h(b) etc. This has
the advantage, in our reactive model, of creating variables whose value
can be inspected when they are trying to figure out what went wrong.

Intermediate variables are already possible, by defining properties whose value is an expression. Few people used them in the user study.

@LeaVerou
Copy link
Member Author

LeaVerou commented Aug 9, 2017

One issue with the pipe syntax is that it's not directional, nothing indicates flow, whereas something like >> would (or then, linguistically instead of schematically).

@karger
Copy link
Collaborator

karger commented Aug 13, 2017

Sorry; paper deadline. I'll try to keep up the discussions.

I like the then syntax; also makes it less likely users will consider it counterintuitively contradicting the normal a(b(c function application order. Note that the first function in the then chain can be allowed to take multiple arguments; (f then g then h)(x,y).

Also note potential ambiguity if some exprs return functions; e.g. f then g (x) (y) could mean ((f then g)(x))(y) or (f then g(x))(y)

As for intermediate values, I know they are possible; my point was that maybe they should be encouraged (preferentially over complex expressions), not least because they make debugging easier.

@betaveros
Copy link
Contributor

As a little bit of prior art: F# and Elm (and maybe others) offer << and >> for function composition and <| and |> for function application.

@LeaVerou
Copy link
Member Author

Some more prior art: VueJS and AngularJS support "filters" for formatting data, which are basically functions, and they are combined with a pipe (|). They are used without parentheses if no arguments, and with parentheses if arguments are desired.

See https://vuejs.org/v2/guide/filters.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants