To go along with replacing backslash closure syntax with ||-delimited closure args, what if we also did the same to types?
i.e. instead of writing Str, Str -> Str, you write |Str, Str| Str.
That brings a nice syntactic symmetry with the implementation:
foo: |Str, Str| Str
foo = |a, b| "Hello ${a} and ${b}"
And, as a side-note, it resolves a long frustrating part of the parser: parsing function types in tuples / tag unions / records. When done with lookahead and/or backtracking (as is currently done), this can lead to exponential behavior in the parser. It's possible to parse without backtracking, but the parser gets rather messy.
we definitely need -> or => in the type! :big_smile:
I think the arrow still works with this:
foo: |Str, Str| -> Str
foo = |a, b| "Hello ${a} and ${b}"
Just for my OCD:
foo : |Str, Str| -> Str
foo = |a, b| "Hello ${a} and ${b}"
this is an interesting idea to me for a different reason than the ones discussed so far: the current function type syntax doesn't have an obvious way to represent a zero-arg function, but this actually would!
can someone get me up to speed why the ! at the end of the name is not enough already to signify side effects? (I'm guessing for stuff like standalone types)
lue said:
can someone get me up to speed why the
!at the end of the name is not enough already to signify side effects? (I'm guessing for stuff like standalone types)
Yeah, exactly that.
yeah, like for example anonymous functions and types of functions that take other functions as arguments
I think |...| -> ... could be nice
if we do that, I realized they actually can be nested in types without parens
map : |List a, |a| -> List b| -> List b
because | only ends the args list if it's followed by either -> or =>
otherwise it's opening a nested function type
although I don't love how that looks :laughing:
Oh yeah....didn't think about nesting...works but is not as nice as parents for readability
Anything nested should have proper open/close brace pairs as delimiters
map : |List a, (|a| -> List b)| -> List b
today:
map : List a, (a -> List b) -> List b
today definitely looks nicest to me :big_smile:
for higher order function types
If only the lambda syntax could also match the current type annotations... oh wait :grimacing:
there is the question of how the current syntax would represent the type of a function with no arguments
one possibility:
run! : => {}
run! = ||
# ...
Why don’t we just do parens around args? It would match the calling syntax
map : (List a, a -> List b) -> List b
run! : () => {}
Tbh I don't dislike that. It may look unexpected the first time but I don't see how this could be interpreted as anything other than 0-arg function.
It would be great to actually ask someone.
# this means a function that takes two numbers and returns a number
fn : Num, Num -> Num
# this one takes one number and returns a string
fn : Num -> Str
# what does this mean?
fn : -> Str
Agus Zubiaga said:
Why don’t we just do parens around args? It would match the calling syntax
map : (List a, a -> List b) -> List b run! : () => {}
in that design, wouldn't the first one need nested parens?
map : (List a, (a) -> List b) -> List b
True
Looks fine, though
imho the extra noise for 99% of type annotations doesn't outweigh the perhaps weird first of impression of fn : => {}
another scenario that doesn't look great with bars in the types: multiline args :sweat_smile:
parse_user_id :
|
Request,
Jwt.Secret,
Instant,
| -> Result UserId [MissingTokenHeader, InvalidJwt Jwt.ParseErr]
parse_user_id = |req, jwt_secret, now|
with the parens idea it could be:
parse_user_id : (
Request,
Jwt.Secret,
Instant,
) -> Result UserId [MissingTokenHeader, InvalidJwt Jwt.ParseErr]
parse_user_id = |req, jwt_secret, now|
today:
parse_user_id :
Request,
Jwt.Secret,
Instant
-> Result UserId [MissingTokenHeader, InvalidJwt Jwt.ParseErr]
parse_user_id = |req, jwt_secret, now|
Today looks great!
I'd only lean towards circle brackets for alignment with our function defs, but since they're different brackets, I don't think its worth it
parse_user_id : |
Request,
Jwt.Secret,
Instant,
| -> Result UserId [MissingTokenHeader, InvalidJwt Jwt.ParseErr]
parse_user_id = |req, jwt_secret, now|
Parens make it look like the function takes a tuple to me
Last updated: Jun 16 2026 at 16:19 UTC