diff --git a/docs/BNF.md b/docs/BNF.md index 62ec763..e2cd365 100644 --- a/docs/BNF.md +++ b/docs/BNF.md @@ -91,9 +91,9 @@ This document defines the syntax (BNF) and semantics of the Myc language, a Lisp - **Vectors (Tuples):** Enclosed in square brackets `[1 2 3]`. Evaluates to a vector/tuple structure. - **Records:** Enclosed in curly braces with keyword keys and any expression as values `{:id 101 :name "Alice"}`. They provide O(1) field access using internal memory layouts. Structural equality `(= {:a 1} {:a 1})` is `true`. -- **Series:** A core concept for financial analysis. Series are "infinite" queues with a maximum length (lookback). - - They are created via the `(series lookback_limit schema)` function. The `schema` can be a record layout (e.g., `{:price :float}`) or a type keyword (e.g., `:float`). - - Example: `(series 100 {:price :float :volume :int})`. +- **Series:** A core concept for financial analysis. Series are "infinite" queues with a maximum length (lookback). + - They are created via `(series lookback_limit)`. The element type is **inferred at compile time** from subsequent `push` calls (Hindley-Milner type inference) — no explicit schema is needed. + - Example: `(series 100)` — the compiler infers the element type from usage. - **Indexing:** You access items in a series by calling it or an extracted field like a function with an integer index: `(my_series 0)`. **Crucially, index `0` represents the most recently pushed item.** Index `1` is the second most recent, and so on (lookback indexing). ## 4. Special Forms and Evaluation logic @@ -137,7 +137,7 @@ The Myc runtime environment provides a collection of built-in functions and macr - `now`: Returns the current timestamp. ### Series & Streaming -- `series`: Creates a new series with a defined layout. +- `series`: Creates a new series. Takes a lookback limit; the element type is inferred at compile time from `push` calls. - `push`: Pushes a new item into a series. - `len`: Returns the current number of elements in a series. - `create-random-ohlc`: Generates a mock Open-High-Low-Close data stream. @@ -160,8 +160,8 @@ The Myc runtime environment provides a collection of built-in functions and macr **Financial Pipelines and Series (with Indexing):** ```clojure (do - ;; Create a series with a typed layout (Struct-of-Arrays under the hood) - (def my_ticks (series {:price :float :volume :int :msg :text})) + ;; No schema needed — the compiler infers the element type from push calls. + (def my_ticks (series 100)) (push my_ticks {:price 10.5 :volume 100 :msg "A"}) (push my_ticks {:price 11.2 :volume 200 :msg "B"}) @@ -296,7 +296,7 @@ user.name **Series with while Loop:** ```clojure (do - (def ticks (series {:price :float})) + (def ticks (series 100)) (def i 0) ;; Push 5 prices into the series diff --git a/src/ast/rtl/series/mod.rs b/src/ast/rtl/series/mod.rs index 0a38886..7db3fd6 100644 --- a/src/ast/rtl/series/mod.rs +++ b/src/ast/rtl/series/mod.rs @@ -64,14 +64,14 @@ pub fn register(env: &Environment) { let final_layout = RecordLayout::get_or_create(fields); Value::Series(Rc::new(RecordSeries::new(final_layout, lookback_limit))) } - _ => panic!("series expects a lookback_limit and a type keyword (:float, :int...) or a schema record (e.g., {{:price :float}})"), + _ => panic!("series: second arg must be a type keyword (:float, :int…) or a schema record ({{:field :type}})"), } }, - ).doc("Creates a new series (ring buffer) with a defined layout and lookback limit.") - .description("First arg is the lookback limit (int), second is either a type keyword (:float, :int, :bool, :text, :datetime) or a schema record ({:field :type}).") + ).doc("Creates a new series (ring buffer) with the given lookback limit.") + .description("Takes a single lookback limit (int). The element type is inferred at compile time from subsequent push calls via HM type inference. The compiler injects a second schema argument automatically; the runtime also accepts an explicit schema for cases where inference is not possible.") .examples(&[ - "(series 100 :float)", - "(series 200 {:price :float :volume :int})", + "(series 100)", + "(do (def s (series 5)) (push s 1.5) (s 0))", ]); // (push series value) -> Void