2017-04-27 89 views
19

these对DSL的无标签的最终解释很酷的注释部分2.3,奥列格Kiselyov展示了如何解决解析问题的一个序列化的DSL表达式一次,解释它多次。拷贝机解释与高阶像差

简单地说,他表示“假一流多态性”的同类型

newtype Wrapped = Wrapped (∀ repr. ExpSYM repr ⇒ repr) 
fromTree :: String → Either ErrMsg Wrapped 

并不令人满意,因为它是不可扩展的:我们必须对每设置的不同Wrapper/fromTree限制repr。因此,我倾向于使用他的解决方案复制解释器。这个问题是关于如何在HOAS中使用该解释器。

具体而言,考虑目标语言绑定以下语言:

class Lam repr where 
    lam :: (repr a -> repr b) -> repr (a -> b) 
    app :: repr (a -> b) -> repr a -> repr b 

我无法给Lam类的声音例如我的复印机解释。下面是我有:

data Dup repr1 repr2 a = Dup {unDupA :: repr1 a, unDupB :: repr2 a} 

instance (Lam repr1, Lam repr2) => Lam (Dup repr1 repr2) where 
    lam f = Dup (lam $ unDupA . f . flip Dup undefined) (lam $ unDupB . f . Dup undefined) 
    app (Dup fa fb) (Dup a b) = Dup (app fa a) (app fb b) 

是否有某种方式来给出一个Lambda递归例如的东西,像我Dup型,不涉及undefined

我也利用this paper,允许单子口译与人道主义组织和机构的lam的更强大的版本,但我没有看到它如何帮助我的实例Dup尝试。使用HOAS版本lam的解决方案将会非常棒!


*:奥列格展示了如何使用定义德布鲁因指数健全的情况下,但我在高阶像差的解决方案很感兴趣。

 class Lam repr where lam :: repr (a,g) b -> repr g (a -> b) app :: repr g (a->b) -> repr g a -> repr g b data Dup repr1 repr2 g a = Dup{d1:: repr1 g a, d2:: repr2 g a} instance (Lam repr1, Lam repr2) => Lam (Dup repr1 repr2) where lam (Dup e1 e2) = Dup (lam e1) (lam e2) app (Dup f1 f2) (Dup x1 x2) = Dup (app f1 x1) (app f2 x2) 
+1

这似乎不太可能。你不能从'(r1,r2) - >(r1,r2)'到'(r1 - > r1,r2 - > r2)'获得,这将需要实现'Lam(Dup r1 r2)' '(Lam r1,Lam r2)'。 –

+0

@ Li-yaoXia对于任意一个“Monad m”,我认为从一个'(a - > m b) - > m(a - > b)'是一样的,直到我读到第二个链接的纸。我支持另一个类似的惊人的解决方案。 – crockeea

+1

@crockeea是一种可以在论文的上下文之外描述的“诀窍”,或者我可以跳到某个页面以便快速了解该如何工作? – jberryman

回答

3

这是不可能的。

要显示一个例子,我首先做的Lam一个很简单的例子:

newtype Id a = Id a 

instance Lam Id where 
    lam (Id f) = Id (\x -> let Id r = f x in r) 
    app (Id f) (Id x) = Id (f x) 

现在,我会让那对Dup小号进行动作的功能:

f :: Dup Id Id Int -> Dup Id Id Int 
f (Dup (Id x) (Id y)) = Dup (Id x*y) (Id y) 

我会,从Lam实例中,能够做到lam f :: Dup Id Id (Int -> Int)。 这可能看起来像

Dup (Id (\x -> x*y)) (Id (\y -> y)) 

它不能进行,因为y是不能从x -Lambda。 (使用undefined代替y这里undefined,抛出运行时错误,只要它不能很好地工作。) 这不是一件很少见的事情:任何时候在其他结果中使用其中一个变量时都会发生这种情况。

我不知道你与Monad -generalized一个更强的要求相当的,但这种情况与其他Monad S,太:例如,与Maybe,你不能把以下为Maybe (Int -> Int),因为这取决于给定的值:

f :: Maybe Int -> Maybe Int 
f m = m >>= \x -> if x > 5 then Just x else Nothing 

(你可以用它fromJust和希望没有人这样做,但它是一样的undefined的解决方案。)只有

undefined之遥,如果一个错误该功能需要t然而,看看其他变量。如果您完全确定它永远不会运行在这样的任何事情上(例如,您将展开/创建限制到经过广泛测试的隐藏模块),那么undefined的方式将起作用。

只是多一个建议:使用更详细的error消息而不是undefined,以防出错出错。

0

在模板Haskell做了一些工作后,我有一个适用于这里的想法。另一种选择是做TH的方式做:

class Fail.MonadFail m => Quasi m where 
    -- All the things here, like inspecting types, generating names, etc. 
    ... 

-- Many instances, including 
instance Quasi IO where ... -- So you can debug your TH 
instance TH.Quasi GHCiQ where ... -- see https://github.com/ghc/ghc/blob/master/libraries/ghci/GHCi/TH.hs#L167 
instance TH.Quasi TcM where ... -- see https://github.com/ghc/ghc/blob/master/compiler/typecheck/TcSplice.hs#L835 

data Q a = { unQ :: forall m. Quasi m => m a } 
instance Quasi Q where ... 

您可以找到Q单子的定义here

的端用户工作的Q单子内,并且它可以由任何内部编译器解释器,或IO单子进行调试等。任何复制由forall处理进行解释。你可以,同样,这样做

data L a = { unL :: forall repr. Lam repr => repr a } 
instance Lam L where ... 

myEndUserThing :: L ((a -> b) -> a -> b) 
myEndUserThing = lam $ \f -> lam $ \x -> app f x 

很容易转换到你需要的任何其他repr,如果你需要更多的功能,只需将其添加到Lam类或创建一个额外功能的派生类。