【发布时间】:2014-10-06 03:14:06
【问题描述】:
我有一个 EDSL,它为数组提供类似列表的组合器(map、zipWith 等)
一些组合器要求某些输入是随机访问的。例如。 Gather 的数据数组在另一个指定的索引处从数据数组中选取元素:
Gather (Manifest [10,11,12]) (Manifest [2,0,0,1,2]) = [12,10,10,11,12]
该语言使用data-reify 包来恢复共享。问题是有时同一子树包含需要提供随机访问的节点和可以顺序计算的节点。让他们共享会破坏后续的评估者。
例如,在下面的树中,我希望 [1,2,3] 继续被共享,但 Manifests 将它们包装为恢复图中的不同节点:
[1, 2, 3]
/ \
Manifest Manifest
| |
| Map (+1)
\ /
Gather
一个更复杂的示例可能包括许多共享节点,所有这些节点都应该变得不同(即使 Map (+1) (Manifest [1,2,3]) 可以共享。
[1, 2, 3]
/ \
Manifest Manifest
| |
Map (+1) Map (+1)
| /|
Map (*2) / |
\ / |
Gather |
\ |
ZipWith (+)
即使我找到了简单案例的解决方案(Gather 直接引用Manifest),它已经涵盖了大部分用例。
欢迎大家指点!
下面是该语言的简单模型。
module NoSharing where
data AST = Manifest [Int]
| Map (Int -> Int) AST
| ZipWith (Int -> Int -> Int) AST AST
| Gather AST -- ^ Data
AST -- ^ Indices
complex = ZipWith (+) gathered indexes
where
gathered = Gather (Map (*2) indexes) indexes
indexes = Map (+1) $ Manifest [1,2,3]
simple = Gather dat indexes
where
dat = Manifest [1,2,3]
indexes = Map (+1) dat
【问题讨论】:
-
你能识别出不应该被构造函数共享的东西,例如所有
Manifests 都不应该共享? -
任何依赖可观察共享的东西都注定是脆弱的,因为 Haskell 没有可观察共享。一些实现允许您通过肮脏的技巧恢复一些共享。如果您希望它可靠,则需要在 DSL 中明确共享。
-
@augustss Observable 共享可能会产生误报,而不是误报,所以它不会破坏任何东西。该程序只会运行得更慢。这似乎是最容易实现的事情。我可能仍然能够以纯粹的方式恢复隐式共享,因为这些术语可以在结构上进行比较。
标签: haskell ghc data-reify