Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a list datatype #261

Closed
sharkdp opened this issue Nov 20, 2023 · 14 comments · Fixed by #443
Closed

Add a list datatype #261

sharkdp opened this issue Nov 20, 2023 · 14 comments · Fixed by #443

Comments

@sharkdp
Copy link
Owner

sharkdp commented Nov 20, 2023

  • 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>?
@irevoire
Copy link
Contributor

irevoire commented Dec 2, 2023

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

@triallax
Copy link
Contributor

  • 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.

@sharkdp
Copy link
Owner Author

sharkdp commented Dec 19, 2023

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.

@triallax
Copy link
Contributor

triallax commented Mar 13, 2024

#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?

@irevoire
Copy link
Contributor

Since you can’t use the | as a unary prefix operator, I don’t think it’ll cause any issues.

@sharkdp
Copy link
Owner Author

sharkdp commented May 16, 2024

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 a List<Row> where Row would be a struct type describing the fields in the CSV table
  • Add a args() -> List<String> function to access CLI arguments (like argv in 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).

@sharkdp sharkdp self-assigned this May 16, 2024
@triallax
Copy link
Contributor

Parse simple JSON arrays [2, 7, 10, …]

Bit tangential, but how would we deal with heterogeneous lists (e.g. [2, "foo"])?

@sharkdp
Copy link
Owner Author

sharkdp commented May 16, 2024

Parse simple JSON arrays [2, 7, 10, …]

Bit tangential, but how would we deal with heterogeneous lists (e.g. [2, "foo"])?

We wouldn't 😄. That is, until we add sum types.

@triallax
Copy link
Contributor

Of course. :)

This was referenced May 16, 2024
@rben01
Copy link
Contributor

rben01 commented Sep 9, 2024

Syntax-wise, I'd prefer JS, (x, y) => x+y. AFAIK the => is not yet used in Numbat.

@Goju-Ryu
Copy link
Contributor

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.

@irevoire
Copy link
Contributor

The simple fn (a, b) is my favorite, I think.
It could also create the general concept of « function as expression ».
And writing let a = fn (a, b) = a + b

@rben01
Copy link
Contributor

rben01 commented Dec 12, 2024

I also like fn(a, b), although I'm not a fan of the equals sign after the declaration. In fn f(a, b) = ... the equals sign represents that we're assigning the function to f, so we can later say “f of (a, b) equals ...“. But in fn(a, b) ... nothing is being assigned to anything — the corresponding statement is just “(fn(a,b) ...) of (a, b) equals ...”. So I think it should just read fn(a, b) a+b. It also just feels correct that fn f(a, b) = ... and let f = fn(a, b) ..., which would be equivalent, would have the same number of = signs (indicating the same number of assignments: 1).

@sharkdp
Copy link
Owner Author

sharkdp commented Dec 27, 2024

Can we please move the lambda-syntax discussion to a new ticket that discusses lambdas in general?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants