语法树:free monad + Bound.Scope

And*_*ris 9 haskell abstract-syntax-tree free-monad

我试图定义使用ekmett的库抽象语法类型boundfree.我有一些工作,我可以删除到以下最小的例子:

{-# LANGUAGE DeriveFunctor #-}

import Bound
import Control.Monad.Free

type Id = String

data TermF f ? =
    AppF ? ?
  | BindF Id (Scope () f ?)
  deriving Functor

newtype Term' ? = T {unT :: Free (TermF Term) ?}
type Term = Free (TermF Term')
Run Code Online (Sandbox Code Playgroud)

最后两行是,呃,不是我所希望的.它们使得PITA实际上可以利用注释(或其他)的开放递归.

是否有更好的方法将这两个库一起使用,和/或我应该放弃尝试制作Term一个免费的monad?

Cir*_*dec 9

简单一点

您可以将最后两行简化为.

newtype Term ? = T {unT :: Free (TermF Term) ?}
Run Code Online (Sandbox Code Playgroud)

这应该可以帮助您确保始终如一地使用T,unT而不是仅在其他所有级别使用.

让它变得复杂

双方FreeTermF有那种(*->*)->(*->*),它是那种一个变压器.您正在寻找的组成的固定点FreeTermF.我们可以编写一般的变压器组成.

{-# LANGUAGE PolyKinds #-}

newtype ComposeT g h f a = ComposeT { unComposeT :: g (h f) a}
    deriving Functor
Run Code Online (Sandbox Code Playgroud)

我们也可以编写变压器的固定点.

{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}

newtype FixT t a = FixT { unFixT :: t (FixT t) a }

deriving instance Functor (t (FixT t)) => Functor (FixT t)
Run Code Online (Sandbox Code Playgroud)

然后你可以写

type Term = FixT (ComposeT Free TermF)
Run Code Online (Sandbox Code Playgroud)

然后使用FixT . ComposeT您刚刚使用的任何地方T以及unComposeT . unFixT您将使用的任何地方unT.