ethereum / moon-lang

Minimal code-interchange format
MIT License
193 stars 20 forks source link

alternative syntax #1

Closed Pyrolistical closed 7 years ago

Pyrolistical commented 7 years ago

I see you are a fan of terse functional programming syntax, but I don't think that is easy for people to pick up.

If you want moon-lang to be easier to learn for the everyday js dev, you'll need to use a more familiar syntax.

I don't think we even need to choose the one-true-syntax. I think we can just have 2 equivalent syntaxes with two different parsers building the same terms. Crazy idea, we can have a single canonical AST that the compiler understands, but have multiple AST/parser/syntaxes. We can then do AST to AST translation bi-directionally. This would mean we can instantly switch between different syntaxes.

Here's my straw man to get the discussion going: https://github.com/Pyrolistical/moon-lang/pull/1/files

Some features:

Additional sugar:

Applying a bunch of sugar would turn:

strings => {
  len = Get(strings, 'length')
  For(0, len, '', i => result => {
    str = Get(strings, String(i))
    Concat(result, str)
  })
}

into

strings =>
  For(0 strings.length, '', i => result =>
    Concat(result, strings[i])
  )

Which you would then promptly replace with reduce

Pyrolistical commented 7 years ago

small poc converting moon code -> moon -> term -> moon ast -> new ast -> new code https://github.com/Pyrolistical/moon-lang/tree/alt-syntax-poc/moon-lunula

VictorTaelin commented 7 years ago

Hey, sorry for the delay! Yes, I absolutely agree my syntax sucks (for most) and indeed the original idea is to have a canonical AST with multiple syntaxes. I'd love a Pythonistic take on it. The thing that I think needs to be agreed is the binary format, which is how Moon code should be transported. This is the output of Moon.pack. An alternative syntax just needs to be able to pack and unpack from that format.

Note that there is still a few minor adjustments that need to be done before the binary format is finalized:

  1. Strings should be packed as unicode (currently they are packed as arrays of nats...);

  2. Floats should be packed as sign + nat (mantissa) + nat (exponent) (currently it is just a nat, so it only works for positive integers);

  3. Free vars names should be packed correctly (not implemented yet);

That is fast to do, but I'm a little bit out of time. Once this is done, we just need to specify that format precisely and let different syntaxes agree in packing/unpacking from it. Makes sense?

Pyrolistical commented 7 years ago

I've written a parser for the syntax I want. https://github.com/concept-not-found/deft/blob/master/parser.spec.js

If we can agree upon the binary format, I can easily bridge this to your runtime

Pyrolistical commented 7 years ago

I translated this: https://github.com/MaiaVictor/moon-lang/blob/master/moon-demo/demo-performance.js#L224-L233

width => {
  buildMatrix = width => {
    buildRow = i => R.range(0, width).map(x => x + i)
    R.range(0, width).map(buildRow)
  }
  sumMatrix = mat => R.sum(mat.reduce(R.concat, []))
  sumMatrix(buildMatrix(width))
}

My idea here is to also port Ramda, so it gets compiled away

VictorTaelin commented 7 years ago

Hey, your syntax looks very nice! I'd like to experiment with it, do you have instructions?

So, yes, we definitely need to agree upon the binary format. There is one thing: are you able to do it the other way around, i.e., recover a "pretty" source code (under your syntax) from the binary specification? That is probably important, because otherwise we couldn't use alternating syntaxes. If so, then we need to preserve variable names on the binary format (they're currently dropped for bruijn indexes). What do you think?

Also, what do you mean by "port Ramda"?

VictorTaelin commented 7 years ago

The binary format was completed on the last commit. I think it is quite good right now, but I'm open to suggestions. The variable naming issue was solved by using bruijn indices on lambdas and names on lets. That format is flexible, as it allows you to completely remove variable names (for smaller bundles), but you can still leave them by using let inside the body; i.e., λ . let foo : var0 in body (notice no var name on λ) can desugar from/to foo => body.

I'll document the details soon, but it is pretty simple and you can look at the source code already. If you develop a small library to convert between your syntax and this binary format (and back), I'll include it on the Mist editor (if that's OK to you).

AnthonyJacob commented 7 years ago

I see you are a fan of terse functional programming syntax, but I don't think that is easy for people to pick up.

Eh, the current syntax is not very terse. You can't even say that functional syntax itself is terse - just look at LISP languages (clojure, scheme).

What actually makes (does not matter if functional or not) language look terse is the use of

width =>
   buildMatrix width =
      buildRow i = map (+i) (range 0 width)
      map buildRow (range 0 widh)

   sumMatrix mat = 
      sum (reduce concat [] mat)

   sumMatrix (buildMatrix width)
VictorTaelin commented 7 years ago

@AnthonyJacob I actually do like your syntax. It looks a lot like my other project, Caramel. Chances are I'll migrate to it eventually. This is why it is important to store things on the binary format, and have a way back.

Pyrolistical commented 7 years ago

The parser isn't very usable atm. My next goal is to decide on my final ast format and translate it to moon term. I can then reuse your binary format and runtime.

What I mean by porting Ramda is to rewrite it in the moon or deft so it can be imported and compiled away.

This allows anybody familiar with js+ramda to easily jump into this

VictorTaelin commented 7 years ago

How will your AST work? Curious to see how you'd do differently.

Pyrolistical commented 7 years ago

Been thinking about how to do recursive references in my syntax, and I came up with this:

{
  fib = n => n > 1
    ? fib(n - 1) + fib(n - 2)
    : n
  fib
}

its a little annoying, but for most cases its fine. in most large programs you'll already define a top level block. the nice is thing i don't need to add any extra syntax, only some additional code when handling function references.

maybe something to consider for moon-lang as well, this way we can remove the @ operator. Ditto for #, you can replace it with an Inline marker function

Pyrolistical commented 7 years ago

feel free to implement syntax for moon, but i won't be working on a bridge to interop with moon now.