Apologies to @Slava_Pestov who seems to care about the type system being sane, and @Douglas_Gregor and @xedin whose dynamic member lookup keypaths allowed me to close the loop on this idea.
Here's the full code, including ~800 lines of state transitions for the BrainFuck VM
. Remember, you need those compiler flags from up above, or this will just time out!
protocol Nat {
static var value: Int { get }
}
struct Zero: Nat {
static var value: Int {
0
}
}
struct Succ<Pred: Nat>: Nat {
static var value: Int {
1 + Pred.value
}
}
/*
print(Succ<Succ<Succ<Zero>>>.value)
*/
// ----
protocol Str {
static var value: String { get }
init()
}
struct EmptyStr: Str {
init() {}
static var value: String {
""
}
}
struct Char<Unicode: Nat, Prefix: Str>: Str {
init() {}
static var value: String {
var result = Prefix.value
result.append(Character(UnicodeScalar(Unicode.value)!))
return result
}
}
/*
typealias A = Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Succ<Zero>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
typealias H = Succ<Succ<Succ<Succ<Succ<Succ<Succ<A>>>>>>>
typealias I = Succ<H>
print(Char<I, Char<H, EmptyStr>>.value)
*/
// ----
protocol MemoryTape {}
struct ToInfinityAndBeyond: MemoryTape {}
struct Square<Value: Nat, Tail: MemoryTape>: MemoryTape {
var value: Value
var tail: Tail
}
// ----
protocol Instr {}
protocol SimpleInstr: Instr {}
struct Exited: Instr {}
struct Inc: SimpleInstr {}
struct Dec: SimpleInstr {}
struct Next: SimpleInstr {}
struct Prev: SimpleInstr {}
struct CharOut: SimpleInstr {}
struct LoopStart: Instr {}
struct LoopEnd: Instr {}
// ----
protocol ProgramTape {}
struct End: ProgramTape {}
struct Instruction<I: Instr, Rest: ProgramTape>: ProgramTape {
var instruction: I
var rest: ProgramTape
}
// ----
protocol MachineState {}
struct Step: MachineState {}
struct ScanForward: MachineState {}
struct ScanBackward: MachineState {}
protocol StateStack {}
struct EmptyStack: StateStack {}
struct Pushed<State: MachineState, Rest: StateStack>: StateStack {}
@dynamicMemberLookup
struct Machine<
TapeLeft: MemoryTape,
TapeCurrent: Nat,
TapeRight: MemoryTape,
ProgramLeft: ProgramTape,
ProgramCurrent: Instr,
ProgramRight: ProgramTape,
Stack: StateStack,
Output: Str
> {
// increment as final instruction
subscript<OutputString, StateTail>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
Succ<TapeCurrent>,
TapeRight,
Instruction<Inc, ProgramLeft>,
Exited,
End,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
ProgramRight == End,
ProgramCurrent == Inc
{
Machine<
TapeLeft,
Succ<TapeCurrent>,
TapeRight,
Instruction<Inc, ProgramLeft>,
Exited,
End,
Stack,
Output
>()[keyPath: keyPath]
}
// increment as nonfinal instruction
subscript<OutputString, StateTail, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
Succ<TapeCurrent>,
TapeRight,
Instruction<Inc, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
ProgramRight == Instruction<NextInstr, Rest>,
ProgramCurrent == Inc
{
Machine<
TapeLeft,
Succ<TapeCurrent>,
TapeRight,
Instruction<Inc, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>()[keyPath: keyPath]
}
// decrement as final instruction
subscript<OutputString, StateTail, Pred>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
Pred,
TapeRight,
Instruction<Dec, ProgramLeft>,
Exited,
End,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeCurrent == Succ<Pred>,
ProgramRight == End,
ProgramCurrent == Dec
{
Machine<
TapeLeft,
Pred,
TapeRight,
Instruction<Dec, ProgramLeft>,
Exited,
End,
Stack,
Output
>()[keyPath: keyPath]
}
// decrement as nonfinal instruction
subscript<OutputString, StateTail, Pred, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
Pred,
TapeRight,
Instruction<Dec, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeCurrent == Succ<Pred>,
ProgramRight == Instruction<NextInstr, Rest>,
ProgramCurrent == Dec
{
Machine<
TapeLeft,
Pred,
TapeRight,
Instruction<Dec, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>()[keyPath: keyPath]
}
// next as final instruction, existing tape
subscript<OutputString, StateTail, TapeRightFirst, TapeRightRest>(dynamicMember keyPath: KeyPath<
Machine<
Square<TapeCurrent, TapeLeft>,
TapeRightFirst,
TapeRightRest,
Instruction<Next, ProgramLeft>,
Exited,
End,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeRight == Square<TapeRightFirst, TapeRightRest>,
ProgramRight == End,
ProgramCurrent == Next
{
Machine<
Square<TapeCurrent, TapeLeft>,
TapeRightFirst,
TapeRightRest,
Instruction<Next, ProgramLeft>,
Exited,
End,
Stack,
Output
>()[keyPath: keyPath]
}
// next as nonfinal instruction, existing tape
subscript<OutputString, StateTail, TapeRightFirst, TapeRightRest, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
Square<TapeCurrent, TapeLeft>,
TapeRightFirst,
TapeRightRest,
Instruction<Next, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeRight == Square<TapeRightFirst, TapeRightRest>,
ProgramRight == Instruction<NextInstr, Rest>,
ProgramCurrent == Next
{
Machine<
Square<TapeCurrent, TapeLeft>,
TapeRightFirst,
TapeRightRest,
Instruction<Next, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>()[keyPath: keyPath]
}
// next as final instruction, creating tape
subscript<OutputString, StateTail>(dynamicMember keyPath: KeyPath<
Machine<
Square<TapeCurrent, TapeLeft>,
Zero,
ToInfinityAndBeyond,
Instruction<Next, ProgramLeft>,
Exited,
End,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeRight == ToInfinityAndBeyond,
ProgramRight == End,
ProgramCurrent == Next
{
Machine<
Square<TapeCurrent, TapeLeft>,
Zero,
ToInfinityAndBeyond,
Instruction<Next, ProgramLeft>,
Exited,
End,
Stack,
Output
>()[keyPath: keyPath]
}
// next as nonfinal instruction, creating tape
subscript<OutputString, StateTail, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
Square<TapeCurrent, TapeLeft>,
Zero,
ToInfinityAndBeyond,
Instruction<Next, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeRight == ToInfinityAndBeyond,
ProgramRight == Instruction<NextInstr, Rest>,
ProgramCurrent == Next
{
Machine<
Square<TapeCurrent, TapeLeft>,
Zero,
ToInfinityAndBeyond,
Instruction<Next, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>()[keyPath: keyPath]
}
// prev as final instruction, existing tape
subscript<OutputString, StateTail, TapeLeftFirst, TapeLeftRest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeftRest,
TapeLeftFirst,
Square<TapeCurrent, TapeRight>,
Instruction<Prev, ProgramLeft>,
Exited,
End,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeLeft == Square<TapeLeftFirst, TapeLeftRest>,
ProgramRight == End,
ProgramCurrent == Prev
{
Machine<
TapeLeftRest,
TapeLeftFirst,
Square<TapeCurrent, TapeRight>,
Instruction<Prev, ProgramLeft>,
Exited,
End,
Stack,
Output
>()[keyPath: keyPath]
}
// prev as nonfinal instruction, existing tape
subscript<OutputString, StateTail, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
ToInfinityAndBeyond,
Zero,
Square<TapeCurrent, TapeRight>,
Instruction<Prev, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeLeft == ToInfinityAndBeyond,
ProgramRight == Instruction<NextInstr, Rest>,
ProgramCurrent == Prev
{
Machine<
ToInfinityAndBeyond,
Zero,
Square<TapeCurrent, TapeRight>,
Instruction<Prev, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>()[keyPath: keyPath]
}
// prev as final instruction, creating tape
subscript<OutputString, StateTail>(dynamicMember keyPath: KeyPath<
Machine<
ToInfinityAndBeyond,
Zero,
Square<TapeCurrent, TapeRight>,
Instruction<Prev, ProgramLeft>,
Exited,
End,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeLeft == ToInfinityAndBeyond,
ProgramRight == End,
ProgramCurrent == Prev
{
Machine<
ToInfinityAndBeyond,
Zero,
Square<TapeCurrent, TapeRight>,
Instruction<Prev, ProgramLeft>,
Exited,
End,
Stack,
Output
>()[keyPath: keyPath]
}
// prev as nonfinal instruction, creating tape
subscript<OutputString, StateTail, TapeLeftFirst, TapeLeftRest, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeftRest,
TapeLeftFirst,
Square<TapeCurrent, TapeRight>,
Instruction<Prev, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeLeft == Square<TapeLeftFirst, TapeLeftRest>,
ProgramRight == Instruction<NextInstr, Rest>,
ProgramCurrent == Prev
{
Machine<
TapeLeftRest,
TapeLeftFirst,
Square<TapeCurrent, TapeRight>,
Instruction<Prev, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>()[keyPath: keyPath]
}
// charout as final instruction
subscript<OutputString, StateTail>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
Succ<TapeCurrent>,
TapeRight,
Instruction<CharOut, ProgramLeft>,
Exited,
End,
Stack,
Char<TapeCurrent, Output>
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
ProgramRight == End,
ProgramCurrent == CharOut
{
Machine<
TapeLeft,
Succ<TapeCurrent>,
TapeRight,
Instruction<CharOut, ProgramLeft>,
Exited,
End,
Stack,
Char<TapeCurrent, Output>
>()[keyPath: keyPath]
}
// charout as nonfinal instruction
subscript<OutputString, StateTail, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<CharOut, ProgramLeft>,
NextInstr,
Rest,
Stack,
Char<TapeCurrent, Output>
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
ProgramRight == Instruction<NextInstr, Rest>,
ProgramCurrent == CharOut
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<CharOut, ProgramLeft>,
NextInstr,
Rest,
Stack,
Char<TapeCurrent, Output>
>()[keyPath: keyPath]
}
// loopstart, nonzero, nonfinal
subscript<OutputString, StateTail, Pred, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopStart, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeCurrent == Succ<Pred>,
ProgramCurrent == LoopStart,
ProgramRight == Instruction<NextInstr, Rest>
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopStart, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>()[keyPath: keyPath]
}
// loopstart, zero, nonfinal
subscript<OutputString, StateTail, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopStart, ProgramLeft>,
NextInstr,
Rest,
Pushed<ScanForward, Stack>,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeCurrent == Zero,
ProgramCurrent == LoopStart,
ProgramRight == Instruction<NextInstr, Rest>
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopStart, ProgramLeft>,
NextInstr,
Rest,
Pushed<ScanForward, Stack>,
Output
>()[keyPath: keyPath]
}
// loopend, zero, final
subscript<OutputString, StateTail>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopEnd, ProgramLeft>,
Exited,
End,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeCurrent == Zero,
ProgramCurrent == LoopEnd,
ProgramRight == End
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopEnd, ProgramLeft>,
Exited,
End,
Stack,
Output
>()[keyPath: keyPath]
}
// loopend, zero, nonfinal
subscript<OutputString, StateTail, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopEnd, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeCurrent == Zero,
ProgramCurrent == LoopEnd,
ProgramRight == Instruction<NextInstr, Rest>
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopEnd, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>()[keyPath: keyPath]
}
// loopend, nonzero, noninitial
subscript<OutputString, StateTail, Pred, PrevInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Rest,
PrevInstr,
Instruction<LoopEnd, ProgramRight>,
Pushed<ScanBackward, Stack>,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<Step, StateTail>,
TapeCurrent == Succ<Pred>,
ProgramLeft == Instruction<PrevInstr, Rest>,
ProgramCurrent == LoopEnd
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Rest,
PrevInstr,
Instruction<LoopEnd, ProgramRight>,
Pushed<ScanBackward, Stack>,
Output
>()[keyPath: keyPath]
}
// scan forward over simple instruction
subscript<OutputString, StateTail, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<ProgramCurrent, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<ScanForward, StateTail>,
ProgramCurrent: SimpleInstr,
ProgramRight == Instruction<NextInstr, Rest>
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<ProgramCurrent, ProgramLeft>,
NextInstr,
Rest,
Stack,
Output
>()[keyPath: keyPath]
}
// scan forward over loopstart
subscript<OutputString, StateTail, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopStart, ProgramLeft>,
NextInstr,
Rest,
Pushed<ScanForward, Stack>,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<ScanForward, StateTail>,
ProgramRight == Instruction<NextInstr, Rest>,
ProgramCurrent == LoopStart
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopStart, ProgramLeft>,
NextInstr,
Rest,
Pushed<ScanForward, Stack>,
Output
>()[keyPath: keyPath]
}
// scan forward over loopend, final
subscript<OutputString, StateTail>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopEnd, ProgramLeft>,
Exited,
End,
StateTail,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<ScanForward, StateTail>,
ProgramRight == End,
ProgramCurrent == LoopEnd
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopEnd, ProgramLeft>,
Exited,
End,
StateTail,
Output
>()[keyPath: keyPath]
}
// scan forward over loopend, nonfinal
subscript<OutputString, StateTail, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopEnd, ProgramLeft>,
NextInstr,
Rest,
StateTail,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<ScanForward, StateTail>,
ProgramRight == Instruction<NextInstr, Rest>,
ProgramCurrent == LoopEnd
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopEnd, ProgramLeft>,
NextInstr,
Rest,
StateTail,
Output
>()[keyPath: keyPath]
}
// scan backward over simple instruction
subscript<OutputString, StateTail, PrevInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Rest,
PrevInstr,
Instruction<ProgramCurrent, ProgramRight>,
Stack,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<ScanBackward, StateTail>,
ProgramCurrent: SimpleInstr,
ProgramLeft == Instruction<PrevInstr, Rest>
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Rest,
PrevInstr,
Instruction<ProgramCurrent, ProgramRight>,
Stack,
Output
>()[keyPath: keyPath]
}
// scan backward over loopend
subscript<OutputString, StateTail, PrevInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Rest,
PrevInstr,
Instruction<LoopEnd, ProgramRight>,
Pushed<ScanBackward, Stack>,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<ScanBackward, StateTail>,
ProgramCurrent == LoopEnd,
ProgramLeft == Instruction<PrevInstr, Rest>
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Rest,
PrevInstr,
Instruction<LoopEnd, ProgramRight>,
Pushed<ScanBackward, Stack>,
Output
>()[keyPath: keyPath]
}
// scan backward over loopstart, nested
subscript<OutputString, StateTail, PrevInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Rest,
PrevInstr,
Instruction<LoopStart, ProgramRight>,
Pushed<ScanBackward, StateTail>,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<ScanBackward, Pushed<ScanBackward, StateTail>>,
ProgramCurrent == LoopStart,
ProgramLeft == Instruction<PrevInstr, Rest>
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Rest,
PrevInstr,
Instruction<LoopStart, ProgramRight>,
Pushed<ScanBackward, StateTail>,
Output
>()[keyPath: keyPath]
}
// scan backward to instruction after loopstart, nonnested
subscript<OutputString, StateTail, NextInstr, Rest>(dynamicMember keyPath: KeyPath<
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopStart, ProgramLeft>,
NextInstr,
Rest,
Pushed<Step, StateTail>,
Output
>,
OutputString
>) -> OutputString
where
Stack == Pushed<ScanBackward, Pushed<Step, StateTail>>,
ProgramCurrent == LoopStart,
ProgramRight == Instruction<NextInstr, Rest>
{
Machine<
TapeLeft,
TapeCurrent,
TapeRight,
Instruction<LoopStart, ProgramLeft>,
NextInstr,
Rest,
Pushed<Step, StateTail>,
Output
>()[keyPath: keyPath]
}
}
extension Machine where ProgramCurrent == Exited {
var output: Output {
.init()
}
}
// +++[->+++<]>[->++++>++++++++>+++++++++<<<]>>.+.<----.>>++.++++.<.---.>---.
typealias PrintHi = Machine<
ToInfinityAndBeyond,
Zero,
ToInfinityAndBeyond,
End,
Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<LoopStart,
Instruction<Dec,
Instruction<Next,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Prev,
Instruction<LoopEnd,
Instruction<Next,
Instruction<LoopStart,
Instruction<Dec,
Instruction<Next,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Next,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Next,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Prev,
Instruction<Prev,
Instruction<Prev,
Instruction<LoopEnd,
Instruction<Next,
Instruction<Next,
Instruction<CharOut,
Instruction<Inc,
Instruction<CharOut,
Instruction<Prev,
Instruction<Dec,
Instruction<Dec,
Instruction<Dec,
Instruction<Dec,
Instruction<CharOut,
Instruction<Next,
Instruction<Next,
Instruction<Inc,
Instruction<Inc,
Instruction<CharOut,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<Inc,
Instruction<CharOut,
Instruction<Prev,
Instruction<CharOut,
Instruction<Dec,
Instruction<Dec,
Instruction<Dec,
Instruction<CharOut,
Instruction<Next,
Instruction<Dec,
Instruction<Dec,
Instruction<Dec,
Instruction<CharOut,
End>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>,
Pushed<Step, EmptyStack>,
EmptyStr
>
protocol Infer {
associatedtype InferredType
static var inferFrom: InferredType { get }
}
struct PrintHiOutput: Infer {
static let inferFrom = PrintHi().output
}
print(PrintHiOutput.InferredType.self)
print(PrintHiOutput.InferredType.value)