Hacker News new | ask | show | jobs
by OriPekelman 683 days ago
Actually looks quite interesting. syntax looks like:

  fun
  | is_sorted([] || [_]): #true
  | is_sorted([head, next, tail, ...]):
     head .<= next && is_sorted([next, tail, ...])

  is_sorted([1, 2, 3, 4, 5])
  is_sorted([1, 2, 30, 4, 5])
a bunch of ways to express blocks, pattern matching and macros. The class facilities also look very nice. other than some indentation it doesn't feel pythony at all (which for me is a good thing!) more like an Elixir feel (cute syntax for some great concepts behind) see https://github.com/racket/rhombus/blob/master/demo.rhm
2 comments

For a person that doesn't know racket, Haskell or any ML it looks unnecessarily convoluted.

My most charitable take is that it solves some problems I never seen a computer language have.

The above is a super concise syntax example that showcases multiple things at the same time. It is function definition mixed with pattern matching, with some advanced pattern matching features, like the '...' and '||' symbols. You can rewrite the example into the code below, if you find it to be more readable.

    fun is_sorted(list):
      match list:
      | []: #true
      | [_]: #true
      | [head, next, tail, ...]:
          head .<= next && is_sorted([next, tail, ...])
There's also a dot in `head .<= next`, because the syntax is sugar for `head.<=(next)`. Not sure why this is needed, but a quick read on the docs suggests this is done to enable static dispatch for some calls.
Not sure that can be called sugar when it it has just as many characters, two spaces rather than two brackets, with remaining lexies in same order, and the cognitive load is at least as important as it exposes the dot-notation within an infix three characters operator.

The global project might be nice, but in this particular case it's kind of opt for worst of all pre-existing conventions while trying to please everyone. The challenge is tough, so that's no wonder it will have hard time matching the goal.

It doesn't look terrible but colon after "match list" is optional.

And how would the last line look if the previous one didn't end in a colon?

Do you know why the tail is needed? Like, what would be the problem with this:

    fun is_sorted(list):
      match list:
      | []: #true
      | [_]: #true
      | [head, next, ...]:
          head .<= next && is_sorted([next, ...])

    ~ $ racket -I rhombus
    Welcome to Racket v8.13 [bc].
    > fun is_sorted(list):
        match list:
        | []: #true
        | [_]: #true
        | [head, next, ...]:
            head .<= next && is_sorted([next, ...])

    ; readline-input:6:19: next: cannot use repetition binding as an expression
    ;   in: next
    ; [,bt for context]

From there I got to "repetition binding" in the docs: https://plt.cs.northwestern.edu/pkg-build/doc/rhombus/Repeti...

From what I can understand, the "..." isn't independent of the previous expression in the list (as I would have expected from e.g. Prolog or Haskell). Instead you are defining a kind of pattern to reuse later, so tail gives a name to the rest of the list (so that it doesn't get associated with next).

Ah, now that makes sense, the three dots need to be assigned to a variable. It's just how they do it is completely new to me. Thank you for finding out!
I wondered this too, let's find out. I am looking all this up as I go, partially as an experiment to find out how easy it is to use Rhombus.

    $ raco pkg install rhombus --auto
which should work if you have some vaguely recent install of racket on your machine and handle the dependencies without prompting.

(I started installing this several hours ago on a slow machine but it's still going.)

It's supposed to take a couple of minutes.

Please file a bug report so this can be tracked down.

https://github.com/racket/rhombus

I'm not going to file a bug report, that's more time than I'm willing to spend on a project I'm not involved in. I will say I'm using Termux 0.118 and Racket 8.13 on kernel 5.10 and Android 14 and am willing to answer questions.
As someone who has it doesn’t look convoluted and solves problems I’ve seen many computer languages have, especially non-functional-style ones.
What does | solve?

They are also using : ; , and a new line. Also ' and << >> that I have no idea how to type.

They are using both :~ and :: for type hints.

In none of the languages I've seen that was necessary or useful.

I think the problem they were solving was ... we really want to be able to cram everything into one line, so even if you split lines you might just as well still use the same characters despite them being unnecessary then.

The syntax `expr :~ annot` is used to annotate the expression with static information. This is different from type annotations.

It's a general mechanism to associate an expression with "extra information" that can be used elsewhere (at compile time).

One can for example using static information to implement dot notation for an object system. Using static information, one can push name resolution from runtime to compile time.

The important part is that users of Rhombus can use the mechanism for tracking static information specific for their programs.

It will be exciting to see the creative uses of this mechanism in the future.

https://docs.racket-lang.org/rhombus/static-info.html

> The syntax `expr :~ annot` is used to annotate the expression with static information.

Compiler can tell if a thing is static or dynamic and apply the correct behavior. Why would I ever want to check static thing only dynamically and why would I ever want to try statically check dynamic type if not by mistake?

If programmer doesn't really have a real choice why make him choose which buttons to press?

The idea behind macros is so to speak to allow the programmer to extend the compiler.

In a language like MetaPost I can use equations between variables:

   x + y = 10
   x - y =  6
A reference to a variable x will use the current set of equations and solve for x. The solution (it it exists) will become the value of the variable reference.

Let's say I want to extend Rhombus with this new kind of variable (let's call them linear variables).

Each linear variable needs to have some static information attached. Here the relevant information is the set of equations to consider. A reference to a linear variable will then reduce (at compile time) the equations associated with the variable. The reduced set of equations is then used to generate runtime code that finds the value.

In a sense "static information attached to an expression" is just a convenient way of working with compile time information (in the sense currently used by macros in Racket).

I'm a bit confused: Can this static information system be used for run-of-the-mill static type checking as well or not? And if so, does a static type checker for this language exist or is one in the works?
> Can this static information system be used for run-of-the-mill static type checking as well or not?

Yes.

As an example Matthew Flatt has implemented Shplait in Rhombus:

https://github.com/mflatt/shplait

Looks like Haskell.
Or like Standard ML.

But it's interesting, since I hadn't seen that part yet, only the loop part and some of the dynamic typing.

  for List:
    each i: [1, 2]
    each j: ["a", "b", "c"]
    [i, j]

  > [[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"], [2, "c"]]

  for (i: 1..4):
    "number " +& i
    ~into List

  > ["number 1", "number 2", "number 3"]

  for:
    each:
      friend: ["Alice", "Bob", "Carol"]
      index: 1..4
    println(index +& ". " +& friend)
  1. Alice
  2. Bob
  3. Carol
It gave me the impression of more of a cross between Scheme and Python.
Yes, I also got Python vibes. That behind said, I'm digging infix less and less over time, and I'm actually starting to crave forth syntax, just got the complete lack of punctuation...

but, I actually really like what they have going here. Seems nice and minimalist, while meeting consistent and clean.