Context
The question in the title is actually the general version of the specific problem that I have. Feel free to answer a general question or this specific question below.
I am implementing some function that traverses the purely untyped AST lambda calculus and replaces variables with the De-Bruijn indices. There are two AST representations, external (with variable names) and internal (with indexes):
type Id = String data TermEx = VarE Id | LamE Id TermEx | AppE TermEx TermEx data TermIn = VarI Int | LamI TermIn | AppI TermIn TermIn
A quick overview of how De-Bruijn indexing works on page 6 of this pdf:
http://ttic.uchicago.edu/~pl/classes/CMSC336-Winter08/lectures/lec4.pdf
Current solution
A regular recursive function that does what I want:
encode' :: TermEx -> TermIn encode' = go [] where go en te = case te of VarE x -> case elemIndex x en of Just i -> VarI LamE xt -> LamI $ go (x:en) t AppE tt' -> AppI (go en t) (go en t') -- * see comment below
Comment: The AppI annotation function application is a split in the AST, and each split creates a new βlocalβ state.
Question
Ideally, I want to describe this as some kind of monadic calculation that keeps track of a new local state every time an AST breaks up, my first attempt:
type DeBruijn = forall m. (Monad m, Functor m) => StateT [Id] m TermIn
does not work, since all branches will share the same state, discarding the index. So, how do you describe this apparently very general calculation scheme?
source share