Add a list datatype
- What kind of syntax do we want for lists?
- How do we want to add lists in the type checker? What should be the syntax for defining list types?
List<T>?
What should be the pattern to work with it?
I see two big paths personally;
- Should it be iterative, and thus, should we add mutability and loop to the language
- Or should it be functional, and thus there are multiple ways to implement it in any case, we'll need a new syntax for anonymous functions:
- Like Python, with global functions everywhere:
count(filter(map(list, fn (price) price * 50%), fn (price) price < 10))(I hate it very much) - Like most iterative sane language with methods, but then, should we implement some kind of objects?
list.map(fn (price) price * 50%).filter(fn (price) price < 10).count() - Like functional language with some kind of symbol to chains function call (here I used OCaml cool
|>symbol);list |> map fn (price) price * 50% |> filter fn (price) price < 10 |> count
- Like Python, with global functions everywhere:
- Like functional language with some kind of symbol to chains function call (here I used OCaml cool
|>symbol);list |> map fn (price) price * 50% |> filter fn (price) price < 10 |> count
We could maybe do this with //, but extending it to accept partial applications of functions.
What should be the pattern to work with it?
Those are good questions, and I currently don't have an answer. I certainly see Numbat as a kind of functional programming language. As for the lambda syntax, I personally prefer the Rust style |price| price × 50% compared to Python (lambda price: price × 50%) or Haskell \price -> price × 50%. As for the chaining/filtering syntax, I need to think about it.
https://github.com/sharkdp/numbat/pull/398 also brings up the question of whether we should also add (heterogeneously-typed) tuples and not just lists. Thoughts?
I personally prefer the Rust style |price| price × 50% compared to Python (lambda price: price × 50%) or Haskell \price -> price × 50%.
I really dislike the Python syntax personally (also doesn't really fit in with the rest of the Numbat syntax), but a bit more on the fence about Rust-style vs Haskell-style syntax. Would the Rust-style syntax possibly introduce parsing difficulties if we decide to add | as a bitwise OR operator later?
Since you can’t use the | as a unary prefix operator, I don’t think it’ll cause any issues.
Some cool things we could do with lists:
- Implement functions like
mean,variance, etc. in Numbat - get rid of variadic functions
- Parse simple JSON arrays
[2, 7, 10, …] - Parse CSV files, either as
List<List<Scalar>>or as aList<Row>whereRowwould be astructtype describing the fields in the CSV table - Add a
args() -> List<String>function to access CLI arguments (likeargvin C) - Add a plot-function based on a list of x and y values
- Repeatedly call functions like
rand_normal(…), store all results in a list, then plot the distribution — something I recently wanted to do, but had to write in Rust (calling into Numbat). - …
Parse simple JSON arrays [2, 7, 10, …]
Bit tangential, but how would we deal with heterogeneous lists (e.g. [2, "foo"])?
Parse simple JSON arrays [2, 7, 10, …]
Bit tangential, but how would we deal with heterogeneous lists (e.g.
[2, "foo"])?
We wouldn't :smile:. That is, until we add sum types.
Of course. :)
Syntax-wise, I'd prefer JS, (x, y) => x+y. AFAIK the => is not yet used in Numbat.
Syntax-wise, I'd prefer JS,
(x, y) => x+y. AFAIK the=>is not yet used in Numbat.
I personally would prefer the same style as well, but there is a pretty good argument against it as well. Right now numbat declares what kind of language construct will follow with a keyword. Like structs, let bindings and functions and even lists, it would be beneficial to have the first token be exclusive to lambdas or possibly functions as well.
I consider the following possibilities to be good compromises between a widely recognizable style and one in line with numbats style.
|a, b| = a + b
|a, b| => a + b
fn (a, b) = a + b
\(a, b) = a + b
\(a, b) => a + b
I don't particularly like the Haskell inspired ones though, as they are a bit of a pain to write on danish keyboards. I like keeping the arguments in parentheses though to keep it consistent with the normal functions. I have put an arrow or equal sign between parameters and body in each as I think that will lessen the strangeness to people without rust experience and allow more people to intuitively understand the syntax without knowing it.