numbat icon indicating copy to clipboard operation
numbat copied to clipboard

Anonymous functions and/or pipelining?

Open bsidhom opened this issue 1 year ago • 3 comments

Thought of how this might be useful when trying to work around #305. I'm picturing being able to do something such as the following:

1 / 30 mpg -> L / km // (fn(x) = x * 100)

In the above scenario, the main benefit is clarity. You could scale the incoming value, but then it's unclear what's going on. In any case, you're still "lying" about the units, so it's not sufficient to actually address #305. Operator precedence of // also makes this a bit nicer, though the parentheses above are a bit annoying.

Partial function application via // could also make this a bit less annoying, e.g.:

fn scale(a, x) = a * x
1 / 30 mpg -> L / km // scale(100)

As noted above, this example is technically incorrect because the units display incorrectly given the intention.

In general, there are a lot of directions to go in terms of syntax, so I'm not sure what this would best look like. The focus should probably be on ergonomics and making things obvious and unambiguous without tons of parens.

bsidhom avatar Feb 23 '24 12:02 bsidhom

Just noticed #261 while searching for similar issues. That contains a discussion about pipelines and partial function application.

bsidhom avatar Feb 23 '24 12:02 bsidhom

when trying to work around #305

Just a note: a workaround is to introduce a new unit:

>>> unit liter_per_100km = liter per 100 km
>>> 1 / 30 mpg -> liter_per_100km

    = 7.84049 liter_per_100km    [Area]

sharkdp avatar Feb 25 '24 21:02 sharkdp

As for the original issue: Yes, we definitely want:

  • Closures: see https://github.com/sharkdp/numbat/issues/347
  • Lambdas: no ticket yet, but see comments in #261, like you mentioned

Things I'm not yet sure about:

  • Do we want partial function application "by default"? Or would users have to curry/uncurry manually, i.e. write scale as fn scale(a) = |x| a * x and then use it with expr -> scale(10).
  • Do we need anonymous functions if we have closures and lambdas?
  • Do we want to keep both expr // fn and expr -> fn? Right now, they are not 100% equivalent, expr // fn can only be used for "proper" functions, while expr -> fn can also be used for other callables (function pointers), like in now() -> tz("Europe/Berlin")

sharkdp avatar Feb 25 '24 21:02 sharkdp

I think this can be closed. The important discussions are in the linked tickets.

sharkdp avatar Jul 02 '24 16:07 sharkdp