考虑由自由变量参数化的lambda项的这种表示形式。(参见Bellegarde和Hook的论文1994,Bird和Paterson的论文1999,Altenkirch和Reus的论文1999)。
data Tm a = Var a
| Tm a :$ Tm a
| Lam (Tm (Maybe a))
您当然可以使它成为Functor
,捕获重命名的概念,并Monad
捕获替代的概念。
instance Functor Tm where
fmap rho (Var a) = Var (rho a)
fmap rho (f :$ s) = fmap rho f :$ fmap rho s
fmap rho (Lam t) = Lam (fmap (fmap rho) t)
instance Monad Tm where
return = Var
Var a >>= sig = sig a
(f :$ s) >>= sig = (f >>= sig) :$ (s >>= sig)
Lam t >>= sig = Lam (t >>= maybe (Var Nothing) (fmap Just . sig))
现在考虑封闭的术语:这些是的居民Tm Void
。您应该能够将封闭项嵌入具有任意自由变量的项中。怎么样?
fmap absurd :: Tm Void -> Tm a
当然,要注意的是,此功能将遍历术语“什么都不做”。但这比坦诚相待unsafeCoerce
。这就是为什么vacuous
被添加到Data.Void
...
或写一个评估者。这是中包含自由变量的值b
。
data Val b
= b :$$ [Val b] -- a stuck application
| forall a. LV (a -> Val b) (Tm (Maybe a)) -- we have an incomplete environment
我只是将lambda表示为闭包。通过将自由变量映射a
到上的值的环境来对评估程序进行参数设置b
。
eval :: (a -> Val b) -> Tm a -> Val b
eval g (Var a) = g a
eval g (f :$ s) = eval g f $$ eval g s where
(b :$$ vs) $$ v = b :$$ (vs ++ [v]) -- stuck application gets longer
LV g t $$ v = eval (maybe v g) t -- an applied lambda gets unstuck
eval g (Lam t) = LV g t
你猜到了。评估任何目标的封闭条件
eval absurd :: Tm Void -> Val b
更一般而言,Void
很少单独使用它,但是在您想要以某种方式表示某种不可能的方式实例化类型参数时非常方便(例如,在此处使用封闭变量free)。通常,这些参数化类型在高阶函数的参数提升操作的操作对整个类型(例如,在这里,fmap
,>>=
,eval
)。因此,您可以通过absurd
进行通用操作Void
。
再举一个例子,假设使用Either e v
捕获希望为您提供计算v
但可能会引发type异常的计算e
。您可能会使用此方法来统一记录不良行为的风险。为了在此设置中表现良好的计算,请e
设为Void
,然后使用
either absurd id :: Either Void v -> v
安全运行或
either absurd Right :: Either Void v -> Either e v
将安全组件嵌入不安全的世界。
哦,还有最后一个呼啦,处理“不可能发生”。它显示在通用的拉链构造中,光标无法到达的任何地方。
class Differentiable f where
type D f :: * -> * -- an f with a hole
plug :: (D f x, x) -> f x -- plugging a child in the hole
newtype K a x = K a -- no children, just a label
newtype I x = I x -- one child
data (f :+: g) x = L (f x) -- choice
| R (g x)
data (f :*: g) x = f x :&: g x -- pairing
instance Differentiable (K a) where
type D (K a) = K Void -- no children, so no way to make a hole
plug (K v, x) = absurd v -- can't reinvent the label, so deny the hole!
我决定不删除其余部分,即使它们并不完全相关。
instance Differentiable I where
type D I = K ()
plug (K (), x) = I x
instance (Differentiable f, Differentiable g) => Differentiable (f :+: g) where
type D (f :+: g) = D f :+: D g
plug (L df, x) = L (plug (df, x))
plug (R dg, x) = R (plug (dg, x))
instance (Differentiable f, Differentiable g) => Differentiable (f :*: g) where
type D (f :*: g) = (D f :*: g) :+: (f :*: D g)
plug (L (df :&: g), x) = plug (df, x) :&: g
plug (R (f :&: dg), x) = f :&: plug (dg, x)
实际上,也许是相关的。如果您喜欢冒险,这篇未完成的文章将介绍如何使用Void
自由变量压缩术语的表示形式
data Term f x = Var x | Con (f (Term f x)) -- the Free monad, yet again
从a Differentiable
和Traversable
functor 自由生成的任何语法中f
。我们Term f Void
用来表示没有自由变量的区域,并[D f (Term f Void)]
用来表示通过没有自由变量的区域隧穿到孤立的自由变量或到两个或多个自由变量的路径中的结点的管道。必须在某个时间完成那篇文章。
对于没有值的类型(或至少没有一个值得礼貌的公司说),Void
它非常有用。以及absurd
如何使用它。
absurd
本文已使用此函数处理Cont
monad:haskellforall.com/2012/12/the-continuation-monad.html