HN
Today

Super Mario Derivations

This article brilliantly demonstrates the power of Nix's lazy evaluation, an often-misunderstood core feature, by applying it to an unconventional problem. The author cleverly represents Super Mario Bros. 3 button sequences and game states as Nix derivations, effectively turning the Nix store into a game save history. It's a compelling, practical exploration that showcases Nix's capabilities far beyond package management, appealing to those who love innovative uses of technical tools.

7
Score
1
Comments
#7
Highest Rank
11h
on Front Page
First Seen
Aug 14, 10:00 PM
Last Seen
Aug 15, 8:00 AM
Rank Over Time
14791011131417202019

The Lowdown

The article dives into the often-surprising lazy evaluation feature of the Nix language and its profound implications, illustrating how this characteristic enables complex structures like those found in Nixpkgs. It then takes this concept to an unexpected and creative extreme: using Nix to simulate Super Mario Bros. 3.

  • Nix's laziness means only accessed attributes are evaluated, permitting "endless" recursion in attribute sets without immediate termination. This is exemplified by pkgs.pkgs.pkgs.hello yielding the same store path, or an infinitely deep countdown attribute set where only indexed values are computed.
  • This lazy, recursive nature is applied to Super Mario Bros. 3, where each attribute path represents a sequence of button presses. Each node in the tree is a game frame, and children are button presses leading to new frames.
  • The system generates a Nix derivation for each frame/button press, with each derivation taking the previous press's savestate as an input. This ensures that frames are not re-emulated, and the Nix store effectively becomes a history of game savestates.
  • This design allows for efficient branching: building a new sequence that shares a prefix with an existing one only computes the divergent presses, reusing all common ancestor derivations from the store.
  • A .play suffix in the attribute path stitches together all generated frames into a video, leveraging the pre-computed frames already present in the Nix store via symlinks for optimal performance.
  • The author identifies practical limits: Nix's max-call-depth caps path length (around 20,000 presses) due to nested calls, and the kernel's MAX_ARG_STRLEN limits argument size (around 21,845 presses). These can be overcome by adjusting max-call-depth or providing the input sequence via a file.
  • Build times for these derivations are linear per press. Surprisingly, the round-trip cost for checking cache substituters is a more significant bottleneck than the actual frame emulation.

This innovative project demonstrates that Nix's attribute paths are not merely names but rather "programs" that can lazily generate content. It highlights Nix's potential as a robust persistence layer for reproducible state machines, extending its utility well beyond conventional package management to fascinating applications like game emulation.