matz / streem

prototype of stream based programming language
MIT License
4.6k stars 237 forks source link

Streem examples #46

Open tbodt opened 9 years ago

tbodt commented 9 years ago

So far, it seems that the only thing anybody knows how to write with Streem is the FizzBuzz and cat programs. Obviously, a language can't be that useful if it can only do FizzBuzz and cat.

Please comment on this issue with your examples of more useful things you can do with Streem. I still need to be convinced that there are any.

nickserv commented 9 years ago

Keep in mind that Streem is in its really early phase of development. As far as I'm aware, not much is implemented yet besides parsing source files. There's still a bit of design discussion going on. That being said, Streem already has a few pretty cool conceptual ideas, like functional programming concepts and sending one stream to multiple consumers.

alexispurslane commented 9 years ago

Heres an idea though:

// Get all usernames from a stream of input data. Assumes my seggestions of currying and prototypal are accepted, as well as my alternative syntax for lambdas.

['username': '', 'age': 0, 'init': (u, a) -> { this.u = u; this.a = a; }] -> User

def ith (n, thing) {
  thing[n]
} // Possible shorthand for: `def ith (n, thing) = thing[n]`, anyone?

ith(0, _) -> get_user

STDIN | split(',', _) | User.init(_, int(_)) | get_user | STDOUT
// The input format could be: Christopher Dumas,22
s-aida commented 9 years ago

If it's premature to add a real-world example, what else? Fibonacci? Prime Numbers? Or even Hello World?

nickserv commented 9 years ago

Hello World

["Hello, world!"] | STDOUT
nickserv commented 9 years ago

Fibonacci

def fib (n) {
  if n == 0 {
    0
  } else if n == 1 {
    1
  } else {
    fib(n-1) + fib(n-2)
  }
}

seq(10) | fib | STDOUT

This is a fairly naive example in terms of performance, but it should work (hopefully).

Edit: Whoops, this seems to be broken with the current streem parser. Any ideas as to what's wrong?

shuichiro-makigaki commented 9 years ago

Currently, I think you can't write fib (n) {. Instead, fib (n) | {. But, this isn't what you'd like to do...

ghost commented 9 years ago

Is it seq(10) | fib | STDOUT. Or

seq(10) | { |x|
  fib(x)
} | STDOUT

and how do you give functions names. More examples, please. Is it like in Haskell?

f x y = x * 2 + y * 2
g = f 2
h = g 3
h == 10
nickserv commented 9 years ago

@blkdev Those should both work, Streem should have first class functions.

matz commented 9 years ago

I added some examples in 2dce6a4. More to come.

tbodt commented 9 years ago

@matz They are great examples. Until now, I didn't think of Streem as a language that could do TCP connections. :sunglasses:

nickserv commented 9 years ago

@matz Cool! Out of curiousity, does "Hello World" | STDOUT work, or does the left side have to be a list?

matz commented 9 years ago

@nicolasmccurdy it should be a list. I'd like to reserve | for bitwise or.

nickserv commented 9 years ago

So is | going away for pipes?

alexispurslane commented 9 years ago

Maybe we could use '>>' for pipes, and '%' for splitting them.

Krysl commented 9 years ago

This example "05chat.strm" makes me confused:

broadcast = chan()
tcp_server(8008) | {|s|
  broadcast | s   # connect to broadcast channel
  s | broadcast   # broadcast incoming message
}

I'm not sure "broadcast | s" means data came from "s" to "broadcast" or came from "broadcast" to "s".

matz commented 9 years ago

@Krysl s is a connection to a client. broadcast | s means data from broadcast will be sent to the client, and s | broadcast means data from the client will be sent to broadcast channel, then all clients connected.

matz commented 9 years ago

@nicolasmccurdy I might confused you. I meant I wanted to reserve | (for scalar values, e.g. numbers and strings) for bitwise-or operation.

jaxrtech commented 9 years ago

Another alternative is using the pipeline operator found in F# that being |> for pipes. I think the just adding the > sign in itself would make it much clearer in which direction things are being piped. So for example 05chat.strm would look like (with s renamed to client for clarity sake):

broadcast = chan()
tcp_server(8008) |> {|client|
  broadcast |> client   # connect to broadcast channel
  client |> broadcast   # broadcast incoming message
}

Or your could pipe it backwards too. I think this looks kinda confusing though:

broadcast = chan()
tcp_server(8008) |> {|client|
  broadcast |> client   # connect to broadcast channel
  broadcast <| client   # broadcast incoming message
}

Though I think as more on an architectural side note, I think this example could be confusing at first glance since its not explicitly clear how the broadcast |> client pipeline is to be executed whether it be:

I think its important to explicitly distinguish that we would rather always run pipelines in an asynchronous manner since it would lend to a concurrent design and you would not have to worry about a pipeline blocking another one especially if ran in an event loop or thread pool.

For example, the order of which the numbers in this example would get printed out is nondeterministic since both pipelines would be running concurrently (unless we added like a join or something between them before sending it to STDOUT):

seq(100) |> STDOUT
seq(100) |> { |x| x * 2 } |> STDOUT

Of course, individual pipes in a single pipeline would always run in a blocking fashion since you have to wait for input to work with (ex: in a |> b, b waits to execute until a sends something)

I think these are important concepts to think about going down the road either way.

alexispurslane commented 9 years ago

:+1: for |> and <|

naturalethic commented 9 years ago

Please see https://github.com/matz/streem/issues/18#issuecomment-67973150

jaxrtech commented 9 years ago

See #18 comment for FizzBuzz in F# too for example.

Krysl commented 9 years ago

How about named pipe?

mkfifo("/tmp/fifo", S_IFIFO|0666)
fifo_in = open("/tmp/fifo", O_WRONLY)
fifo_out = open("/tmp/fifo", O_RDONLY)
STDIN | fifo_in
seq(100) | fifo_in
fifo_out | STDOUT

And make it more simple, may like this

STDIN | [fifo] | STDOUT
seq(100) | fifo

And if a function can be bind to the named pipe, like a filter. 05chat.strm may look like this:

[broadcast] = chan()
[client] = tcp_server(8008)
broadcast | client | broadcast

[FIFO] may looks strange, we may need better symbols. I'm a newbie, I wish this can be helpful.

nickserv commented 9 years ago

@christopherdumas Agreed. That seems very clear to me, and it also looks kinda nice.

alexispurslane commented 9 years ago

"It looks very cool in my opinion!" |> GITHUB

ghost commented 7 years ago

What would be nice is if there would be "cookbook examples" for streem too. Like we have fizzbuzz but what about other popular redirections? File stuff; also perhaps binary ... video, audio ... these things.

One could also do this via named pipes I suppose; just assign special functions to these pipes to act as filters (a bit similar how gstreamer handles source/sinks).

But matz also said that streem is experimental and it probably has lower priority than e. g. mruby so I guess this is stuff that may all happen "at a later time". :)

linbirg commented 4 years ago

fibonacci

def fib (n) { if (n == 0) { 0 } else if (n == 1) { 1 } else { fib(n-1) + fib(n-2) } }

seq(10) | fib | stdout

Fibonacci

def fib (n) {
  if n == 0 {
    0
  } else if n == 1 {
    1
  } else {
    fib(n-1) + fib(n-2)
  }
}

seq(10) | fib | STDOUT

This is a fairly naive example in terms of performance, but it should work (hopefully).

Edit: Whoops, this seems to be broken with the current streem parser. Any ideas as to what's wrong?

fibonacci

def fib (n) { if (n == 0) { 0 } else if (n == 1) { 1 } else { fib(n-1) + fib(n-2) } }

seq(10) | fib | stdout

if add () is ok for now.