package ast import "fmt" type Visitor[T any] interface { VisitAtom(*Atom) T VisitAbstraction(*Abstraction) T VisitApplication(*Application) T } func Visit[T any](visitor Visitor[T], node Expression) T { switch node := node.(type) { case *Atom: return visitor.VisitAtom(node) case *Abstraction: return visitor.VisitAbstraction(node) case *Application: return visitor.VisitApplication(node) default: panic(fmt.Sprintf("unknown node %t", node)) } }