As @Li-yaoXia pointed out, you need a recursion point at each constructor you want to analyze. My initial definition of Stmt
was incorrect because the `SAssign` constructor that models variable binding was a "leaf".
This is a better definition that actually models nested variable scopes:
data Stmt a = SAssign Id (Stmt a) -- id = ..; smt
| SSeq [Stmt a] -- smt0; smt1; ..
| SIf (Stmt a) (Stmt a) -- branching
deriving (Show)
-- | base functor of Stmt
data StmtF a x = SAssignF Id x -- id = ...; smt
| SSeqF [x] -- smt0; smt1; ..
| SIfF x x
deriving (Eq, Show, Functor, Foldable, Traversable)
instance Semigroup (Stmt a) where
(<>) = undefined -- we only need mempty
instance Monoid (Stmt a) where
mempty = SSeq []
s0 :: Stmt a
s0 = SAssign 0 (SIf (SAssign 1 mempty) (SAssign 2 mempty))
gives us at last
λ> scanCofree (<>) mempty $ binds s0
[0] :< SAssignF 0 ([0] :< SIfF ([0,1] :< SAssignF 1 ([0,1] :< SSeqF [])) ([0,2] :< SAssignF 2 ([0,2] :< SSeqF [])))