And*_*rew 6 haskell functional-programming functor
我有一些GADT代表lambda演算中的一个术语.
data Term a =
Var a
| Lambda a (Term a)
| Apply (Term a) (Term a)
Run Code Online (Sandbox Code Playgroud)
我想要做的是在该类型上有一个通用的转换接口.它应该具有类似于此的类型签名:
(Term a -> Term a) -> Term a -> Term a
Run Code Online (Sandbox Code Playgroud)
编写此函数很容易:
fmap' :: (Term a ? Term a) ? Term a ? Term a
fmap' f (Var v) = f (Var v)
fmap' f (Lambda v t) = Lambda v (fmap' f t)
fmap' f (Apply t1 t2) = Apply (fmap' f t1) (fmap' f t2)
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是haskell(或haskell库)中有某种通用结构来进行这种转换(类似于Functor
它应该叫做态射)?
pig*_*ker 12
供参考,以下是术语......
data Term a =
Var a
| Lambda a (Term a)
| Apply (Term a) (Term a)
Run Code Online (Sandbox Code Playgroud)
(我注意到变量的表示是抽象的,这通常是一个很好的计划.)
......这是建议的功能.
fmap' :: (Term a ? Term a) ? Term a ? Term a
fmap' f (Var v) = f (Var v)
fmap' f (Lambda v t) = Lambda v (fmap' f t)
fmap' f (Apply t1 t2) = Apply (fmap' f t1) (fmap' f t2)
Run Code Online (Sandbox Code Playgroud)
让我对这个定义感到困扰的是,f
它只适用于表单的术语(Var v)
,所以你也可以实现替换.
subst :: (a ? Term a) ? Term a ? Term a
subst f (Var v) = f v
subst f (Lambda v t) = Lambda v (subst f t)
subst f (Apply t1 t2) = Apply (subst f t1) (subst f t2)
Run Code Online (Sandbox Code Playgroud)
如果你把稍微注意区分自由变量绑定的,你可以让Term
一个Monad
具有替代实现(>>=)
.通常,术语可以具有Functor
用于重命名的Monad
结构和用于替换的结构.Bird和Paterson有一篇可爱的论文,但我离题了.
同时,如果你确实想要在变量之外采取其他行动,那么一种通用方法是使用通用遍历工具包,例如uniplate,正如augustss所暗示的那样.另一种可能性,也许稍微有点自律,是为你的类型使用'折叠'.
tmFold :: (x -> y) -> (x -> y -> y) -> (y -> y -> y) -> Term x -> y
tmFold v l a (Var x) = v x
tmFold v l a (Lambda x t) = l x (tmFold v l a t)
tmFold v l a (Apply t t') = a (tmFold v l a t) (tmFold v l a t')
Run Code Online (Sandbox Code Playgroud)
这里v
,l
并a
定义一个替代代数您Term
-形成操作中,只作用于y
,而不是Term x
,解释如何处理变量,lambda表达式和应用.您可以选择y
是m (Term x)
对一些合适的单子m
(例如,线程的变量的环境中),而不仅仅是Term x
本身.处理每个子项以给出a y
,然后选择适当的函数来产生y
整个项.折叠捕获标准递归模式.
普通的一阶数据类型(以及一些表现良好的高阶数据类型)都可以配备折叠运算符.以可读性为代价,您甚至可以一劳永逸地编写折叠运算符.
data Fix f = In (f (Fix f))
fixFold :: Functor f => (f y -> y) -> Fix f -> y
fixFold g (In xf) = g (fmap (fixFold g) xf)
data TermF a t
= VarF a
| LambdaF a t
| ApplyF t t
type Term a = Fix (TermF a)
Run Code Online (Sandbox Code Playgroud)
与递归不同Term a
,这TermF a t
解释了如何使用子项中的元素创建一个术语的一个层t
.我们Term
使用递归Fix
类型返回递归结构.我们在美容上会失去一点,因为每层都有额外的In
包裹.我们可以定义
var x = In (VarF x)
lambda x t = In (LambdaF x t)
apply t t' = In (Apply x t t')
Run Code Online (Sandbox Code Playgroud)
但我们不能在模式匹配中使用这些定义.然而,回报是我们可以免费使用通用产品fixFold
.要计算一个y
术语,我们只需要给出一个类型的函数
TermF a y -> y
Run Code Online (Sandbox Code Playgroud)
其中(就像v
,l
以及a
以上)解释了如何处理其子项已被处理为类型值的任何术语y
.通过明确关于一个层包含的类型,我们可以逐层挖掘工作的一般模式.
归档时间: |
|
查看次数: |
666 次 |
最近记录: |