Closed asoffer closed 3 years ago
I don't really have context on when a'f
is used, but you could just make that the syntax for currying
Then a'f()
is invocation and a'f(b)
is calling a
's method f
with argument b
.
While I don't love using /
(it is a bit overloaded in the language of Will's cognitive processing), the above wouldn't necessarily be the worst substituting '
with /
or ,
or .
Comparing with the two methods for invoking f
at the top, I wonder if my proposal is:
1) Prefix function invocation is (arg)'function
2) Prefix function currying is arg'function
Thus, arg'function
should also work to invoke a function. And for multiple arguments one could curry them all and then invoke:
3) a'b'function()
(note, this is not guaranteed to be as efficient as just invoking, unless the compiler can elide unnecessary currying)
In general, if one wants to immediately invoke the function, they should prefer
4) (a,b)'function
The bad news with this proposal is that it requires an optimization when currying and immediately invoking with additional args on the right. The other oddity is "what function is actually invoked in (3)?"
The optimizations aren't particularly an issue. If the double-currying is spelled that way in source it could be elided, but I'm also fine if it's not. Our goals on performance are about letting the user eke out every last drop, not about requiring them to.
My concern though is: Is (a + b)'function
curried? In other words, what if we need parentheses for grouping as well?
requiring parens afterwards for a function call is interesting though and could be a nice way to distinguish a call vs currying. That being said, then a double-curried f(a, b)
would be written as (b'(a'f))()
which doesn't look great. The parentheses are needed because '
should be left-associative to make call-chaining work.
We could also make a'f(b)
be it's own ternary-ish operator separate from '
and give them different associativities.
You should never need to double curry and call, right?
But b'(a'f)
is still ugly
So let's see an example of call chaining
a'f()'g()
=> (a'f())'g()
?
note I don't see why you wouldn't write that as f(a)'g() unless f is a method on a
Problem
Icarus does not provide anything like class member functions, which makes what would otherwise be a short-named function much longer: Example from C++
Equivalent in Icarus
The problem is the need to prefix
append
withstr.
. C++ and other languages with class member functions effectively use the type as a namespace for functions acting on that type. As Icarus doesn't allow this, it makes a lot of functions more verbose than counterparts in similar languages.Proposal
Currently there are two ways to call a function:
func(a, b)
(a, b)'func
The proposal is to allow
a'func(b)
as well and have all arguments preceding the function contribute to argument-dependent lookup. This would allow us to calls'append("abc")
becauseappend
would be looked up in the module definingstr.String
.A caveat
There is one caveat here that would require addressing. We do not currently allow this interpretation of
a'func(b)
because it is interpreted as(a'func)(b)
. In other words, ifa: A
andb: B
,a'func(b)
would requirefunc
to have signatureA -> B -> C
, but we would want it to be(A, B) -> C
.Interestingly, there's a nice correspondence between these two function types that ML-style languages take advantage of. We would need to ban overload sets consisting of
(A, B) -> C
andA -> B -> D
as they would be ambiguous. However, if one subscribes to the idea that all overloads in an overload set should do effectively the same thing, then any such overloads should really have been such that one is a curried version of the other. In that case, we just need to find another way to express currying. There's lots of syntactic real-estate for that (needs closures as a language feature). A few examples:f[a]
f/a
a/f
a -> f