private TiState Step(TiState state)
        {
            var headAddr = state.Stack.Peek();
            var headNode = state.Heap[headAddr];

            return(headNode switch
            {
                TiNode.Number number => StepNum(state, number),
                TiNode.Application application => StepAp(state, application),
                TiNode.Supercombinator supercombinator => StepSc(state, supercombinator),
                TiNode.Indirection indirection => StepInd(state, indirection),
                TiNode.Primitive primitive => StepPrim(state, primitive),
                TiNode.Data data => StepData(state, data),

                _ => throw new ArgumentOutOfRangeException(nameof(headNode))
            });
        private (IReadOnlyDictionary <int, TiNode> Heap, IReadOnlyDictionary <Name, int> Globals) BuildInitialHeap(IEnumerable <SupercombinatorDefinition <Name> > supercombinatorDefs)
        {
            var heap    = new Dictionary <int, TiNode>();
            var globals = new Dictionary <Name, int>();

            foreach (var def in supercombinatorDefs)
            {
                var addr = heap.Count;

                heap[addr]        = new TiNode.Supercombinator(def.Name, def.Parameters, def.Body);
                globals[def.Name] = addr;
            }

            foreach (var(name, type) in _primitives)
            {
                var addr = heap.Count;

                heap[addr]    = new TiNode.Primitive(name, type);
                globals[name] = addr;
            }

            return(heap, globals);
        }