5 ms·
I've been cautiously optimistic about Rhombus since the initial "Racket 2" controversy. I'd have preferred they went with something more like Wisp or Wraith, bu
by Y_Y 2y ago
I've been cautiously optimistic about Rhombus since the initial "Racket 2" controversy. I'd have preferred they went with something more like Wisp or Wraith, but it could be a lot worse.
I am somewhat troubled by tricks that are "too magic", like this example from front page:
class Posn(x, y)
fun flip_all([Posn(x, y), ...]):
[Posn(y, x), ...]
flip_all([Posn(1, 2), Posn(3, 4)])
// ⇒ [Posn(2, 1), Posn(4, 3)]
Why should the later Posns be flipped? That's certainly not what I would expect.
(Then again being too magic is working well for Python, e.g. that a<b<c thing)
- norman784 2y agoCare you to elaborate on Racket 2 controversy? I don't follow the language, but I'm aware of it, so I didn't learn about the controversy.
- Y_Y 2y agoe.g. https://beautifulracket.com/appendix/thoughts-on-rhombus.html https://beautifulracket.com/appendix/thoughts-on-rhombus.htm...
- soegaard 2y agoIt's not magic. It's pattern matching. The `[Posn(x, y), ...]` is a pattern that matches a list of positions. The `[Posn(y, x), ...]` is a template that produces a list of positions.
- arunix 2y agoThat syntax suggests the first pair will be flipped, and the rest will just be as they were, i.e. more like flip_first
- soegaard 2y agoWhen the pattern `[Posn(x, y), ...]` matches a list of positions, since `Posn(x, y)` is followed by `...` the `x` is bound to a sequence of first coordinates and `y` is bound to a sequence of second coordinates. In the template the `Posn(y, x)` is followed by `...` so the same number of positions is produced as the common length of x and y.
- Y_Y 2y agoTypical pattern matching like in Haskell or Prolog wouldn't do this.
- laszlokorte 2y agoWhat would be the corresponding syntax for matching and flipping only the first Posn? If I had to guess: fun flip_all([Posn(x, y), rest]): [Posn(y, x), rest] If I am correct then the only difference between flipping all and flipping just the first is `...` vs `rest`
- Jtsummers 2y agoYour version would expect a list of two elements, you use & to indicate that you're collecting the remainder of the list as in: fun flip_all([Posn(x, y), & rest]): You'd need to amend the logic of the function body to iterate or recurse over the remainder. You'd also ended up with a nested list using your version but you can use & again to splice in the result, so if you wanted a recursive version of that it would be something like (skipping the base case): fun | flip_all([]): [] | flip_all([Posn(x, y), & rest]): [Posn(y, x), & flip_all(rest)] (not tested, don't have Rhombus available on this system but that should be correct) If you really want flip_first it'd be: fun flip_first([Posn(x, y), & rest]): [Posn(y, x), & rest]
- Y_Y 2y agoIn Haskell: flip_one Posn(a,b) = Posn(b,a) flip_first p:ps = flip one : ps flip_all ps = map flip ps To my taste that's a lot nicer
- disconcision 2y agoa big part of the racket project has been about establishing robust tools for transforming syntax. focusing on this use case has resulted in a much more generalized notion of pattern matching and template reconstruction than is typical. these kind of pattern/template combinators, as developed for racket/match and syntax-parse, might appear special-casey at first glance but from use i can attest that they are clean and compositional... they have the appearance of something you'd write informally on a whiteboard, but they really do just work, and the rules are fairly simple and easy to internalize. Here, the ... pattern combinator means 'match a list (segment) consisting of the pattern Posn(x,y) zero or more times, and because (free variables) x and y are under one ... combinator, bind x to a list of xs and y to a list of ys'. The template combinator ... means 'produce a list (segment) consisting of the template Posn(x, y) zero or more times, returning an error unless x and y are bound to lists. The reason I specified 'under one combinator' for the pattern part is that ellipses can be nested, resulting in contained pattern variables being bound to lists of lists etc. anyway, point is, this is all just compositional rules, with no spooky communication needed between pattern and template. I won't objectively argue that it's not magic, but it's at least not more magic than regexps.
- Y_Y 2y agoI understand what it's doing, I just don't like that it does it.
- notjack 2y agoAre you familiar with `syntax-rules` based macros? Because this is roughly the same logic here. It's trying to unify how macros produce syntax objects via `syntax-rules`-style pattern matching and ellipses with how regular pattern matching on values works, so there aren't two separate pattern languages (one for macros and one for everything else).
- Y_Y 2y agoI am only have a passing acquaintance with them I'm afraid, though I have been meaning to get my head around it and write a few hashlangs. https://docs.racket-lang.org/guide/pattern-macros.html#(part._.Matching_.Sequences) https://docs.racket-lang.org/guide/pattern-macros.html#(part... I like the explanation there, and I think it gets me closer to my objection. I'm quite happy with the Kleene Star as a concept, but I don't think it corresponds to any usual use of ellipsis, nor is it really a list element on equal footing with the others.