Julia: Use `\mapsto` ( ↦ ) for anonymous functions

Created on 10 May 2015  ·  30Comments  ·  Source: JuliaLang/julia

It would be nice to be able to use the correct mathematical notation " ↦ " (\mapsto) for anonymous functions, x ↦ f(x), in addition to x -> f(x)

This sounds like it should be a relatively easy addition to the parser (but I don't know where to start).

decision

Most helpful comment

I'm going to reopen this as there still seems to be broad interest, and there's no recorded reason for why it was closed.

All 30 comments

+1

If you want to try it out

diff --git a/src/julia-parser.scm b/src/julia-parser.scm
index 36981c0..b4a1423 100644
--- a/src/julia-parser.scm
+++ b/src/julia-parser.scm
@@ -64,7 +64,7 @@
 ; operators that are special forms, not function names
 (define syntactic-operators
   '(= := += -= *= /= //= .//= .*= ./= |\\=| |.\\=| ^= .^= ÷= .÷= %= .%= |\|=| &= $= =>
-      <<= >>= >>>= -> --> |\|\|| && |.| ... |.+=| |.-=|))
+      <<= >>= >>>= -> ↦ --> |\|\|| && |.| ... |.+=| |.-=|))
 (define syntactic-unary-operators '($ & |::|))

 (define syntactic-op? (Set syntactic-operators))
@@ -74,7 +74,7 @@
 (define ctrans-op (string->symbol "'"))
 (define vararg-op (string->symbol "..."))

-(define operators (list* '~ '! '¬ '-> '√ '∛ '∜ ctrans-op trans-op vararg-op
+(define operators (list* '~ '! '¬ '-> '↦ '√ '∛ '∜ ctrans-op trans-op vararg-op
                          (delete-duplicates
                           (apply append (map eval prec-names)))))

@@ -897,7 +897,7 @@
       (case t
         ((|::|) (take-token s)
          (loop (list t ex (parse-call s))))
-        ((->)   (take-token s)
+        ((->  ↦)   (take-token s)
          ;; -> is unusual: it binds tightly on the left and
          ;; loosely on the right.
          (let ((lno (line-number-filename-node s)))

Would it need to be removed from prec-arrow?

Yes, it should be if this were the a formal PR. But -1 on this proposal, I don't like the use of unicode for special forms that have a perfectly sane ascii equivalent.

Similar to #8487

@jakebolewski Great, thanks for the code sample.

I see where you're coming from, but it seems to me that basically all unicode would be excluded by your reasoning, e.g. using α (\alpha) instead of alpha.

From my point of view, one of the points of allowing unicode is that code can resemble hand-written (or LaTeX) equations as much as possible. \mapsto is a nice step in that direction. #8487 is not quite the same, since in maths you don't actually write for i ∈ 1:10.

+1. It seems like there is no other sane meaning for \mapsto other than ->, so if we are going to accept it at all, we might as make the two synonyms. No different from \sqrt for sqrt or \le for <=.

One difference is that it's a special form, so can't be handled with a simple alias.

One counter-proposal: it might be useful to parse \mapsto as a macro @mapsto args body. e.g. @timholy's FastAnonymous package could then make x ↦ f(x) turn into @anon x -> f(x), and in general a package could use this for construction of new function-like objects.

:+1: That's a cool use of the Unicode character!

+1

I really don't think we should make an operator for something that is a stopgap for something that just ought to be fixed.

Reminds me of the macro-parsing of ~ which seems a bit arbitrary to me. If you want macro parsing, shouldn't you use a macro?

Yes, ~ being a macro was surprising

I like @stevengj's idea of allowing a few infix operators as macros, although I'm not sure if is a good candidate for it.

A bit unrelated: I'd really like to use ~> and <~ as aliases for lift in Reactive... e.g. lift(sqrt, signal) would be equivalent to signal ~> sqrt or sqrt <~ signal. Currently this is not possible though.

The reason I suggested a macro for is that if (a) we parse for overloading, the most sensible use for it would be for user-defined function-like syntaxes (FastAnonymous being just one example) and (b) if you want to define your own function-like operator syntax, you kind of need a macro.

It would look less confusing to me to have and -> mean exactly the same thing.

~ is a slightly weird special case, but if anything I'd vote for fixing that by making _more_ operators parse as macros, not fewer – and if that's not feasible I think the benefit of a few special cases outweighs the aesthetic cost. They're really, really useful for making intuitive APIs. As an example of a non-DataFrames use of ~ I'm working on an object system of sorts with syntax

object~method(x, y)

Of course, I could write this as

@call object.method(x, y)

but if you're using the system a lot this adds a ton of noise to the code. It's really nice to have an escape hatch here.

I agree that it wouldn't be right to make this work _specifically_ for FastAnonymous, but as @stevengj says this could have plenty of uses for function-like things (Reactive.jl, function-like operators, etc.).

I was noting that should either parse as macro OR as a synonym for ->, and cannot have both meanings. I agree that is _a_ useful symbol to parse as a macro. One more thing to note: the usefulness of a macro operator will go away if two packages define macros of the same name, i.e. you cannot use the infix notation (for one of them) anymore if both packages are loaded.

@one-more-minute I'm not convinced. In addition to macro-operators being poorly composable due to the lack of namespacing, there's already a quite straightforward escape hatch for dsl's to cut down on macro-call noise:

@dsl begin
    # anything you want
end

Julia's support of Latex notation for unicode makes it really easy to create mathematical DSLs that look and feel like the mathematics we are used to writing. I'm making liberal use of them as operators (\otimes, \circ) myself. However, every time a symbol is reserved in the base language, the ability to do this is diminished. Keep in mind that the same symbol, however standard it may seem to be, ends up used differently in different subfields of math, physics, economics, and so on where Julia may be used. For a non-unicode example, I had to rewrite a lot of code when capital I became UniformScaling, since I was using it to mean the monoidal identity in a monoidal category, where that use is also standard.

Another consideration is that unicode support is still buggy in many places (e.g. the red boxes in saved IJulia notebooks). For example, the default system font in Ubuntu 15.04 causes unicode characters to behave incorrectly (spacing issues causing illegibility or huge spaces) in the Julia terminal and in emacs until the font settings are changed.

You gave us unicode and you can take it away, but let me plead for extreme caution in reserving things.

I'll ask this here, as I did not right away find any other appropriate issue and I guess several of the Unicode & Julia experts are subscribed to this issue. I didn't want to open a new issue right away for something so small.

It's great that \mapsto at least parses as infix operator. Strangely enough, this is not true for \mapsfrom. \leftarrow and \rightarrow both work and could serve as an alternative if there is a good reason why this is the case.

So all of these work, in an expression:

:(a ↦ b)
:(a → b)
:(a ← b)

but this one :(a ↤ b) yields

ERROR: syntax: missing comma or ) in argument list

Any reason why this is so?

\mapsfrom is somehow not included in our list of operators. Probably an oversight. It should be added.

This just came up again on Slack. Maybe it's time to reconsider this?
It actually seems to have been closed prematurely despite quite a few +1s.

+1.

-> is a frequently used construct. Using ↦ will make a lot of code look cleaner / compact / more like pseudocode.

I'm going to reopen this as there still seems to be broad interest, and there's no recorded reason for why it was closed.

I think Jake just decided that he didn't like it.

I can think of several points against this:

  • It adds spurious syntax variations. Code with a mix of -> and would be quite annoying.
  • It's breaking, since this currently parses as a normal function-like operator.
  • https://github.com/JuliaLang/julia/issues/11223#issuecomment-101881412 (which seems to be what triggered the closing): better not to "steal" syntax when we already have decent syntax for something.

I didn't find https://github.com/JuliaLang/julia/issues/11223#issuecomment-101881412 super convincing but you've got some good points.

The mathematician in me really wants this to work so I'm torn. I'll admit that personally I don't even use in code even though I love the look of it. It seems a bit spurious and confusing for readers to have to navigate that syntax variation.

Cascadia code will also do the substitutions that @JeffBezanson linked to in Julia Mono

Was this page helpful?
0 / 5 - 0 ratings