Aspects & Functors
import { Aside } from ‘@astrojs/starlight/components’;
The __functor Pattern
Section titled “The __functor Pattern”In Nix, any attribute set with __functor can be called as a function:
let counter = { value = 42; __functor = self: n: self.value + n; };in counter 8 # => 50The __functor receives self (the attrset) and an argument.
Aspects as Functors
Section titled “Aspects as Functors”Every aspect in flake-aspects has a default __functor:
{ nixos = { a = 1; }; __functor = self: _context: self; # ignores context}By default, it ignores context and returns itself. But you can replace
__functor with one that inspects context:
{ nixos.foo = 24; __functor = self: context: if context ? host then self else { includes = [ fallback ]; };}Aspect Structure
Section titled “Aspect Structure”Aspects have three kinds of attributes:
Owned Configurations
Section titled “Owned Configurations”Direct class settings:
den.aspects.igloo = { nixos.networking.hostName = "igloo"; darwin.nix-homebrew.enable = true; homeManager.programs.vim.enable = true;};Includes
Section titled “Includes”Dependencies on other aspects — a directed graph:
den.aspects.igloo.includes = [ den.aspects.gaming den.aspects.tools._.editors ({ host, ... }: { nixos.time.timeZone = "UTC"; })];Includes can be:
- Static aspects — always included
- Functions — called with context, included when they match
Provides
Section titled “Provides”Nested sub-aspects forming a tree:
den.aspects.gaming.provides.emulation = { nixos.programs.retroarch.enable = true;};Resolution
Section titled “Resolution”When Den needs a NixOS module from an aspect, it calls .resolve:
module = den.aspects.igloo.resolve { class = "nixos"; aspect-chain = [];};graph TD
Asp["den.aspects.igloo"]
Asp --> Owned["owned: nixos, darwin, homeManager"]
Asp --> Inc["includes: gaming, tools._.editors, fn..."]
Asp --> Resolve[".resolve { class = 'nixos' }"]
Resolve --> Collect["Collect all 'nixos' attrs<br/>from aspect + transitive includes"]
Collect --> Module["Single merged Nix module"]
This collects all nixos configs from the aspect and all its transitive
includes into a single Nix module.
Functions vs Aspects
Section titled “Functions vs Aspects”Functions in includes are context-aware:
den.aspects.igloo.includes = [ # static — always included { homeManager.programs.direnv.enable = true; }
# parametric — called with context ({ host, ... }: { nixos.time.timeZone = "UTC"; })
# conditional — only called when context has user ({ host, user, ... }: { homeManager.programs.git.userName = user.userName; })];Den inspects each function’s argument names to decide whether to call it with the current context. See Parametric Aspects for the matching rules.
The den.default Aspect
Section titled “The den.default Aspect”den.default is an aspect with parametric.atLeast functor:
den.default = den.lib.parametric.atLeast { };It dispatches context to all its includes. Since every host, user, and
home includes den.default, it serves as the backbone for global routing.