我尝试使用ekmett的库bound
和free
来定义抽象语法类型。我有一些工作,我可以删除以下最小的例子:
{-# 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')
最后两行是,呃,不是我所希望的。它们使得PITA实际上可以利用开放递归进行注释(或其他)。
有没有更好的方法将这两个库结合使用,和/或我应该放弃尝试让Term
成为免费的monad?
答案 0 :(得分:9)
您可以将最后两行简化为。
newtype Term α = T {unT :: Free (TermF Term) α}
这应该可以帮助您在任何地方始终使用T
和unT
,而不是仅在其他所有级别使用。{/ p>
Free
和TermF
都有类型(*->*)->(*->*)
,这是一种变换器。您正在寻找Free
和TermF
组成的固定点。我们可以编写一般的变压器组成。
{-# LANGUAGE PolyKinds #-}
newtype ComposeT g h f a = ComposeT { unComposeT :: g (h f) a}
deriving Functor
我们也可以编写变压器的固定点。
{-# 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)
然后你可以写
type Term = FixT (ComposeT Free TermF)
然后在您使用FixT . ComposeT
的任何地方使用T
到处使用unComposeT . unFixT
和unT
。