I have this simple Expr
AST and I can easily convert it to String
.
import Prelude hiding (Foldable)
import qualified Prelude
import Data.Foldable as F
import Data.Functor.Foldable
import Data.Monoid
import Control.Comonad.Cofree
data ExprF r = Const Int
| Add r r
deriving ( Show, Eq, Ord, Functor, Prelude.Foldable )
type Expr = Fix ExprF
testExpr = Fix $ Add (Fix (Const 1)) (Fix (Const 2))
convertToString :: Expr -> String
convertToString = cata $ \case
e@(Const x) -> show x
e@(Add x y) -> unwords [x, "+", y]
Now I want to add an additional data to it.
So I am trying to use Cofree
type LineNumber = Int
type Expr2 = Cofree ExprF LineNumber
I can convert Expr
to Expr2
addLineNumbers :: Expr -> Expr2
addLineNumbers = cata $ \case
e@(Const _) -> 1 :< e
e -> 2 :< e
But I cannot figure out how to convert Expr2
to String
convertToString2 :: Expr2 -> String
convertToString2 = cata $ \case
e@(_ :< (Const x)) -> show x
e@(_ :< (Add x y)) -> unwords [x, "+", y]
Also, is Cofree the best way to solve this annotation problem?
Free
is inductive andCofree
is coinductive. That is, tearing down a (well-behaved) free monad using a (total) algebra for an arbitrary functor is guaranteed terminating, and building up a cofree comonad using a coalgebra is guaranteed productive. The other way round is not true – Swingletree