Open edemaine opened 1 year ago
For class
and multiple of the same keys we should have some way of aliasing but I'm not sure of the best syntax for it yet.
Perhaps {class: klass === "hi"}
or {class: klass is "hi"}
? Eh, maybe that looks like an expression that should be evaluated and passed in as the class value to match.
I think we also need to improve the default behavior when there are duplicate or keyword names. Some options:
_
or 1
suffix or something.1
suffix, second gets a 2
suffix, etc.0
gets an array of matches, like how in Hera $0
is [$1, $2, ...]
.I also feel like the most common case of duplicate names is when we have bound them to constants already. Something that would help in this sort of scenario is to not actually bind variables if they don't get used in the scope of the match. This would also pair nicely with Option 5 above; we'd like to build this array only if it gets used.
A simple workaround for class
and other keywords, at least for now, would be to just not bind those (or use a Ref that the user can't access). At least then the code would compile.
What about adding the same functionality as in #444? To allow something like:
switch a
m := /(\d)/
return m[1]
any plans for guard clauses other than simple binary operators?
@JUSTIVE Yes! I don't think we've settled on a notation yet, but I also may be forgetting a proposal. One obvious thing to allow would be &
shorthand functions:
switch x
& > 0 // equivalent to just "> 0"
isCool(&) // lets you invoke an arbitrary function
The latter is assuming something like #480 gets implemented, so f(&)
/f &
is shorthand for $ => f($)
.
If we just want to write a function condition, we need to somehow distinguish from a regular identifier. For example, [isCool]
already has a meaning: array of length 1, where the element gets named isCool
. Maybe there would be another notation to denote "needs to match the guard of this function". Let us know if you have ideas.
Great to hear that! I just needed the latter one (invoking a function), and the isCool(&)
notation looks fine.
I'm not that familiar with the civet syntax(Just tried it yesterday), so It's not very appropriate for me to suggest an idea, but the array-like syntax looks very exotic. Does Civet's design towards to point-free style? if so, how about just leave 'isCool` alone?
switch x
isCool(&)
"Something"
isCool //equivalent to above
"Nothing"
The trouble is that a pattern of just isCool
is ambiguous. It could mean:
isCool
in a higher scope (e.g. global). We currently write this as ^isCool
.isCool(x)
returns true. I'm proposing writing this as isCool(&)
.else
), assigning a new name isCool
to x
. (This is potentially useful if x
is a complex expression.)You're arguing for option (2). If you'd asked me, I would have guessed that we already implemented (3), as it's what's symmetric with the current meaning of [isCool]
for example. In fact, there's currently no meaning, and given the ambiguity, that might be best...?
Came back to this thread, about a year later. Been using the Civet lightly with joy so far, and I'm writing a post introducing the Civet in my language now, by comparing its features against alternatives (raw js, and typescript with ts-pattern).
The trouble is that a pattern of just
isCool
is ambiguous. It could mean:
- Equality to another variable
isCool
in a higher scope (e.g. global). We currently write this as^isCool
.- Whether
isCool(x)
returns true. I'm proposing writing this asisCool(&)
.- Always match (like
else
), assigning a new nameisCool
tox
. (This is potentially useful ifx
is a complex expression.)You're arguing for option (2). If you'd asked me, I would have guessed that we already implemented (3), as it's what's symmetric with the current meaning of
[isCool]
for example. In fact, there's currently no meaning, and given the ambiguity, that might be best...?
Sorry for forgetting to reply, I was asking for option 2 then, but now I see why it's difficult to do. I was naively thinking 'What if the matching symbol's type is a function, why not let it apply the value?'. and of course, just assumed that 'The function would be a predicate function'. isCool(&) and match when evaluated value is truthy/falsy seems pretty legit to me now.
back to my writings, while comparing with ts-pattern, the Civet's pattern matching also lacks some complicated guard clause, just like F# and ts-pattern. Maybe sounds familiar as old comments above, but I'm imagining something like this:
/* just an option type */
type some<T> = { __type: "some", value: T }
type none = { __type: "none" }
type option<T> = some<T> | none
const grade =
(score: option<number>) =>
switch score
{ __type: "some", value } if value > 80
"A"
{ __type: "some", value } if value > 60
"B"
{ __type: "some", value } if value > 40
"C"
{ __type: "some", value }
"E"
{ __type: "none" }
"F"
the point is, having some conditional expression next to the pattern to narrow down
the example might be inappropriate since the type variant is just some and none, so here's a better one.
const fruitQualifyingResult =
(value: Fruits) =>
switch value
{ __type : "Apple", weigth } if weight > 500
{ __type : "Banana", length } if length > 15
{ __type : "WaterMelon", sweetness } if sweetness > 16
{ __type : "Ok", value }
else
{ __type : "No", value }
(transcribing these from Discord)
[]
const
:class
makes invalidconst
: