Open tbodt opened 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.
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
If it's premature to add a real-world example, what else? Fibonacci? Prime Numbers? Or even Hello World?
["Hello, world!"] | STDOUT
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?
Currently, I think you can't write fib (n) {
. Instead, fib (n) | {
. But, this isn't what you'd like to do...
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
@blkdev Those should both work, Streem should have first class functions.
I added some examples in 2dce6a4. More to come.
@matz They are great examples. Until now, I didn't think of Streem as a language that could do TCP connections. :sunglasses:
@matz Cool! Out of curiousity, does "Hello World" | STDOUT
work, or does the left side have to be a list?
@nicolasmccurdy it should be a list. I'd like to reserve |
for bitwise or.
So is |
going away for pipes?
Maybe we could use '>>' for pipes, and '%' for splitting them.
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".
@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.
@nicolasmccurdy I might confused you. I meant I wanted to reserve |
(for scalar values, e.g. numbers and strings) for bitwise-or operation.
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:
broadcast
to be completely exhausted before moving to the next line.broadcast
to completely finish piping everything to client
. Since we would never know when broadcast
would be completely finished in order to move to the next line, the program would be dead locked waiting when no data is going to be sent in the first place.broadcast
, we would pipe it to client
and then we would get data from client
, we would pipe it to broadcast
. This would be the intended behavior since we essentially want to setup a background listener on either end.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.
:+1: for |>
and <|
See #18 comment for FizzBuzz in F# too for example.
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.
@christopherdumas Agreed. That seems very clear to me, and it also looks kinda nice.
"It looks very cool in my opinion!" |> GITHUB
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". :)
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?
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.
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.