amber-lang / amber-lang/amber

[Feature] Functional operator for input/output redirection

未關閉
#677 1 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
syntax
主要語言
Rust
星號
5.2k
分支
145
平均合併
5 天 3 小時
30 天內合併 PR
7

描述

This proposal aims to introduce an `IO` type for handling `stdin`, `stderr` and `stdout` as a first-class citizen in Amber, and an accompanying infix operator, `<<` which guides I/O flow from inputs to outputs, inspired by C++ syntax.

Below is an example of what that syntax would look like in action:
```js
import { stdin, stdout, stderr, pipe } from "std/io"

let my_pipe = pipe()

stdout << my_fun()
stderr << echo "hello world"
my_pipe << trust $zcat myfile.tar.gz$

// Can also be used as input
trust $tar -x$ << my_pipe
trust $cat$ << stdin

// Or chained together, in which case the resulting statement is the return value of the leftmost
// statement, unless it is a 'sink' (a file path, fd number, or the stdout/stderr/stdin builtins)
stderr << rainbow() << trust $cowsay$ << my_fun() << "./my_file.txt"
// ^~~~~~~~~ meaning this one!

// Sugar for writing to paths
"/my/file" << echo "overwrite file"
"/my/file"+ << echo "append to file"

// Or to arbitrary file descriptors
3 << echo "write to fd 3"

// Redirecting a command's standard error
"log.txt" <<2 trust $something$
let my_output = "log.txt" <<2 trust $or_other$
// Splitting stderr and stdout is expected to be handled implicitly, as a command's return value
// in Amber is its standard output.
```

And this is how it would interact with other types, using Haskell type syntax:

```haskell
-- Implicit cast: here, Cmd is the type of a bash escape expression (`$echo "this syntax"$`)
Cmd -> IO Text

-- Implicit cast: If not handled, the IO type is dropped (existing use, such as `let a = $echo b$`)
Any t => IO t -> t

-- Type interactions for the proposed `<<` I/O chain keyword:

-- Here, the left-hand operator is an IO sink (i.e. builtins `stdout` or `stderr`),
-- so we drop IO to forbid re-chaining.
(<<): Any t => (IO Null -> IO t) -> t
-- The explicit concept of an IO sink as a type may be dropped seeing as functions may bear
-- the `IO Null` type signature. Using Text and Number as below for builtins like
-- `stdout` or `stderr` would be enough. Maybe pipes would be their own type, or just the
-- path to a FIFO file under the hood.

-- Here, the left-hand operator's expression wins out if not a sink, such as chaining functions or commands together
(<<): Any t, Any u => (IO t -> IO u) -> IO t

-- This syntax allows writing into a file path:
(<<): Any t => (Text -> IO t) -> t
-- ... and reading from it:
(<<): Any t => (IO t -> Text) -> IO t

-- Same, for file descriptors:
(<<): Any t => (Number -> IO t) -> t
(<<): Any t => (IO t -> Number) -> IO t
```

Right now this type system makes no distinction between a source and a sink, merely preventing a sink (`IO Null`) from being placed in the middle of an I/O chain.

Whether `IO` should be specified explicitly in function return types, or be implied for all functions is undecided.

_Originally posted in [#235](https://github.com/amber-lang/amber/issues/235#issuecomment-2647442887)_

貢獻指南

這個儲存庫沒有索引到貢獻指南

評估

這個 Issue 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。