我想将 Haskell 函数提升为高阶 lambda 演算编码。这几乎是从 Oleg 的 Typed Tagless Final encoding 中逐字记录的。
class Lam r where
emb :: a -> r a
(^) :: r (r a -> r a) -> (r a -> r a)
lam :: (r a -> r a) -> r (r a -> r a)
instance Lam Identity where
emb = Identity
f ^ x = f >>= ($ x)
lam f = return (f . return =<<) -- call-by-value
eval = runIdentity
我可以将任意 Haskell 类型嵌入到Lam
using 中emb
,但那时我不能(^)
用于应用程序。此外,提升的功能会表现得很懒惰。相反,我必须逐个应用程序来提升它们。
emb1 :: ( Applicative r, Lam r )
=> (a -> b) -> r (r a -> r b)
emb1 f = lam $ \ra -> f <$> ra
emb2 :: ( Applicative r, Lam r )
=> (a -> b -> c) -> r (r a -> r (r b -> r c))
emb2 f = lam $ \ra -> lam $ \rb -> f <$> ra <*> rb
emb3 :: ( Applicative r, Lam r )
=> (a -> b -> c -> d)
-> r (r a -> r (r b -> r (r c -> r d)))
emb3 f = lam $ \ra -> lam $ \rb -> lam $ \rc -> f <$> ra <*> rb <*> rc
>>> eval $ emb2 (+) ^ emb 1 ^ emb 2
3
不过,这是很多样板文件。我想创建一个适用于任何 arity 函数的通用提升函数。我觉得可以使用类似于Printf
'sPrintfType
或fixed-vector
'Cont
类型的东西。我可以使用类型函数指定我想要的内容
type family Low h o
type instance Low () o = o
type instance Low (a, h) o = a -> Low h o
type family Lift r h o
type instance Lift r () o = o
type instance Lift r (a, h) o = r a -> r (Lift r h o)
class Emb r h o where
embed :: Low h o -> r (Lift r h o)
instance ( Lam r ) => Emb r () o where
embed = emb
instance ( Lam r, Applicative r, Emb r h o ) => Emb r (a, h) o where
embed = ?
但是我通过这种方法非常卡住,通常是由于注入问题。我能够通过新类型包装器和作用域类型变量的真正可怕组合来解决注入性问题,但它从未真正进行过类型检查。
这可以用 Haskell 表达吗?