Uiua Documentation

repository·main·Indexed 24 days ago

https://github.com/uiua-lang/uiua

Uiua is a tacit, stack-based array programming language designed for high-level data manipulation and expressive computation. The documentation covers installation via pre-built binaries, Cargo, Nix, or Git, as well as configuration for optional features (audio, webcam, window) and editor/font support. It also includes technical details on the uiua_parser crate, including the Signature struct for stack effects, Geometric Algebra (GA) flavors, and the Leptos-based Editor and Prim components.

Tokens
53.9K
Snippets
159
Records
388
Agent score
80%

What's inside Uiua

  1. What is Uiua and its programming paradigm

    main

    Uiua is an array programming language in the same family as APL, J, and BQN. It focuses on tacit programming, which is the practice of writing code without naming variables. This is achieved by providing multiple ways to weave the flow of data through a program.

    Key Characteristics:

    • Array-Centric: Arrays are the primary data structure. Operations work on entire arrays at once, often replacing traditional control flow constructs.
    • Prefix Notation: Unlike APL or J which use mathematical notation (e.g., 1 + 2), Uiua puts operators to the left of their arguments (e.g., + 1 2). This ensures every function takes the same number of arguments regardless of position.
    • Built-in Media Support: Uiua includes native functionality for working with images, audio, and GIFs.
    • Machine-Sympathetic: The language is designed to leverage contiguous memory and CPU vectorization for performance.
  2. Understand Uiua's execution order and syntax

    main

    In Uiua, operations appear to the left of their arguments. Code is typically read from right to left to determine the order of operations. Code is also executed from top to bottom.

    • Multiple outputs: If code generates multiple outputs, they are displayed on multiple lines.
    • Single line outputs: Outputs generated on the same line will appear on the same line in the output.
    • Grouping: Use parentheses () to make the grouping of functions and arguments visually apparent.
  3. Working with Arguments and Modifiers

    main

    Uiua programs transform lists of arguments. A number literal makes the first argument to the next function called, pushing current arguments to the right.

    Common Modifiers

    Modifiers change how functions behave. They are applied to one or more functions.

    • self (˙): Makes a function take a single value as all of its arguments.
    • backward (˜): Reverses the order of a function's arguments.
    • on (): Keeps the first argument to a function in front of the function's outputs.
    • by (): Keeps the last argument to a function after the function's outputs.
    • dip (): Skips the first arguments and calls the function on later arguments. Can be chained (e.g., ⊙⊙).
    • reduce (/): Applies a function "between" the items of an array (e.g., /+ for sum).
  4. Optimize data storage with Structs of Arrays

    main

    In Uiua, you can optimize memory and performance by using the Struct of Arrays pattern instead of an Array of Structs.

    • Array of Structs: A list of boxed data definitions (e.g., [Person "Alice" 21; Person "Bob" 54]). This involves significant boxing overhead.
    • Struct of Arrays: A single structure where each field is its own array (e.g., Person {"Alice" "Bob"} [21 54]). This is much more efficient and is displayed as a table by the array output formatter.

    Handling Defaults in Structs of Arrays

    When using boxed data definitions with default values in a struct-of-arrays pattern, use the idiom /⍚⊂≡[Definition] to properly initialize lists of default fields and repeat items.

    # Struct of Arrays construction
    ~Person {Name Age Score}
    Person {"Alice" "Bob" "Carol"} [21 54 49] [5 0 12]
    
    # Initializing lists with defaults
    ~Person {Name Age Score ← 0}
    /⍚⊂≡Person {"Alice" "Bob" "Carol"} [21 54 49]
  5. Use Scoped Modules for in-file module declaration

    main

    You can declare modules within a single file using --- delimiters and a name.

    • Exporting: Append a ~ to the module name to export its names into the outer scope.
    • Calling as a function: If a module contains a function named Call or New, you can invoke the module itself as a function.
    • Macros: Append a ! to the module name to make the module's names available as a macro within that scope.
    ---MyMod ~ Go
      Foo ← 5
      Go ← +1
    ---
    Go MyMod~Foo
    
    ---Foo
      Call ← /++1⇡
    ---
    Foo 5
    
    ---Foo
      A ← 10
      F ← +1
      G ← ×2
    ---
    Foo!(G F ×A) [1 2 3]
  6. How index macros work

    main

    Index macros allow you to define functions that use placeholders to refer to arguments passed during the macro call. These macros act similarly to modifiers, taking function arguments and modifying how they are used.

    Key Rules:

    • Placeholders: Use ^ followed by a number (the index of the function argument) to represent a placeholder. ^0 can be shortened to ^.
    • Naming: A named macro must end with a number of ! characters equal to the number of functions it takes.
    • Hygiene: Index macros are hygienic, meaning they won't accidentally capture or be interfered with by bindings in the surrounding scope.

    Use index macros when you want to define a custom modifier.

    ReduceRange! ← /^0+1⇡
    ReduceRange!+5
    ReduceRange!×4
  7. Track intermediate results with [scan]()

    main

    The scan() modifier is similar to reduce(), but instead of returning only the final result, it returns an array of all intermediate results produced during the reduction process.

    This is particularly useful when applied to a mask to progressively change the mask's state (e.g., zeroing out a mask after a certain condition is met).

  8. Looping with repeat()

    main

    The repeat() modifier (glyph: ) takes a number and calls its function that many times.

    Key behaviors:

    • Scalar input: Calls the function $N$ times where $N$ is the input.
    • Boolean input: Since booleans are numbers in Uiua, repeat()ing with a boolean will call the function 0 or 1 times, making it useful for conditional execution.
    • Extra outputs: If the function produces more outputs than arguments, the extra outputs are collected into arrays.
    • Random generation: A common pattern for generating lists of random numbers is [repeat]()random().
  9. Tag arrays with debug-only Labels

    main

    Labels allow you to attach a debug-only name to an array using the $ prefix followed by an identifier.

    Key behaviors:

    • Visibility: Labels are only visible in debugging outputs (like normal interpreter output or args()). They are not shown when using &p or format strings.
    • Multiple Labels: You can label multiple values within an array using [].
    • Storage: Labeled arrays cannot be placed in a standard array together unless they are boxed (using {}).
    • Removal: Use $_ to remove a label from a value.
    • Limitation: Labels are for debugging only; they cannot be retrieved or manipulated via code.

    Correct vs Incorrect usage:

    • [$a 1 $b 2 $c 3] is incorrect (will fail because they are different types).
    • {$a 1 $b 2 $c 3} is correct (uses boxing).
    $Numbers [1 2 3]
    ⊓$Foo$Bar °⊂ [2 3 5 7]
    ⊸$_ $Label [1 2]
  10. Understanding Uiua's dynamic typing model

    main

    Uiua is a dynamically-typed array language. While array shapes and scalar types can often be determined at compile-time, they are not guaranteed to be static. Types and shapes that depend on user input, environmental factors, or randomness can only be resolved at runtime.

    Because of this dynamism, Uiua functions do not require explicit type signatures for inputs or outputs, allowing them to operate polymorphically across different types and shapes. This simplifies writing code but requires care in large-scale maintainability.

    # Example of a function working on different shapes and types
    F ← ⊂↯
    F 4 0 [1 2 3]
    F 3 [1 2] [3_5 5_6]
    F 8 @U "iua"
  11. Use Data Functions to manage complex arguments

    main

    Data functions allow you to use the fields of a data definition as bundled arguments to a function. This simplifies managing functions with many arguments. To define a data function, add code after a data definition. The field names of the data definition are in scope within this code. When the data definition is called as a function, its constructor is called and then passed to the function.

    Named Optional Arguments

    Data functions support named optional arguments using the un ° and by ⊸ idiom. You can set default values in the data definition using the syntax. Optional arguments are set by calling the function as a macro.

    ~F {A B} +⊃A B
    F 1 2
    F @a ¯12_8_20_0_¯64
    
    # With optional arguments
    ~F {X Y ← 1|Z ← 1} $"X=_,Y=_,Z=_" ⊃(X|Y|Z)
    F 5
    F!°⊸Z 10 5
    F!(°⊸Y 0 °⊸Z 4) 1
    F!°⊸⊃Y Z 0 4 1
    
    # Not all arguments must be fields
    ~Append {N ← 1} ˜⊂▽N
    Append 5 1_2_3
    Append!°⊸N 4 5 1_2_3