Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 带HOAS的复印机-解释器_Haskell_Ghc_Dsl - Fatal编程技术网

Haskell 带HOAS的复印机-解释器

Haskell 带HOAS的复印机-解释器,haskell,ghc,dsl,Haskell,Ghc,Dsl,在DSL无标记最终解释器的非常酷的注释的第2.3节中,Oleg Kiselyov展示了如何解决一次解析序列化DSL表达式,然后多次解析它的问题 简单地说,他展示了类型的“假一级多态性” newtype Wrapped = Wrapped (∀ repr. ExpSYM repr ⇒ repr) fromTree :: String → Either ErrMsg Wrapped 不令人满意,因为它是不可扩展的:对于repr上的每一组约束,我们必须使用不同的包装器/fromTree。因此,我倾向

在DSL无标记最终解释器的非常酷的注释的第2.3节中,Oleg Kiselyov展示了如何解决一次解析序列化DSL表达式,然后多次解析它的问题

简单地说,他展示了类型的“假一级多态性”

newtype Wrapped = Wrapped (∀ repr. ExpSYM repr ⇒ repr)
fromTree :: String → Either ErrMsg Wrapped
不令人满意,因为它是不可扩展的:对于
repr
上的每一组约束,我们必须使用不同的
包装器
/
fromTree
。因此,我倾向于使用他的复印机-解释器解决方案。这个问题是关于如何在HOA中使用该解释器

具体来说,考虑以下语言的目标语言绑定:

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)
对于像my
Dup
类型这样的不涉及
未定义的
的对象,是否有某种方法可以给出
Lambda
的递归实例

我还尝试使用功能更强大的
lam
from版本,该版本允许使用HOA的一元翻译器,尽管我不知道它对我的
Dup
实例有什么帮助。将
lam
的任何一个版本与HOA结合使用的解决方案都非常棒


*:Oleg演示了如何使用de Bruijn索引定义声音实例,但我对HOA的解决方案非常感兴趣


班级报告在哪里
lam::repr(a,g)b->repr g(a->b)
应用程序::repr g(a->b)->repr g a->repr g b
数据Dup repr1 repr2 g a=Dup{d1::repr1 g a,d2::repr2 g a}
实例(Lam repr1,Lam repr2)=>Lam(Dup repr1 repr2),其中
lam(Dup e1 e2)=Dup(lam e1)(lam e2)
app(Dup f1 f2)(Dup x1 x2)=Dup(app f1 x1)(app f2 x2)
这是不可能的

为了展示一个示例,我将首先创建一个非常简单的
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
s上运行的函数:

f :: Dup Id Id Int -> Dup Id Id Int
f (Dup (Id x) (Id y)) = Dup (Id x*y) (Id y)
Lam
实例,我将能够执行
lamf::Dup Id Id(Int->Int)
。 这看起来像

Dup (Id (\x -> x*y)) (Id (\y -> y))
无法创建,因为
y
无法从
x
-lambda获取。(此处使用
undefined
s将
y
替换为
undefined
,在运行时出错时抛出。) 这种情况并不罕见:只要在另一个结果中使用一个变量,就会发生这种情况

我不太清楚你对更强的
单子
的要求是什么,但是其他
单子
也会发生这种情况:例如,对于
Maybe
,你不能将以下内容转换为
Maybe(Int->Int)
,因为它取决于给定的值:

f :: Maybe Int -> Maybe Int
f m = m >>= \x -> if x > 5 then Just x else Nothing
(您可以在它上面使用
fromJust
,希望没有人这样做,但它与
未定义的解决方案相同。)

但是,
undefined
s仅在函数需要查看其他变量时才会抛出错误。如果您绝对确定它永远不会在这样的东西上运行(例如,您将展开/创建限制在经过广泛测试的隐藏模块上),则
未定义的
方法将起作用


还有一个建议:使用更详细的
错误
消息,而不是
未定义
,以防出现问题。

在使用模板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
monad的定义

最终用户在
Q
monad中工作,它可以由任何内部编译器解释器解释,也可以由
IO
monad进行调试等。任何复制都由
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

la
可以轻松地转换为您想要的任何其他
repr
,如果您需要更多功能,只需将其添加到
Lam
类或创建一个具有额外功能的派生类。

这似乎不太可能。你不能从
(r1,r2)->(r1,r2)
(r1->r1,r2->r2)
,这将是使用
(Lam r1,Lam r2)
实现
Lam(Dup r1 r2)
所需要的,对于任意
单子m
,我对从a
(a->(a->mb b)->m(a->b)
,也有同样的想法,直到我读到第二篇链接文章。我在等待另一个类似的令人惊奇的解决方案。@crockeea是一个可以在论文背景之外描述的“技巧”,或者我可以跳转到某一页快速了解其工作原理吗?“不纯但卫生代码的组合器”的第3节有很好的描述,特别是第28页,一个解决方案是从HOA转换到PHOA,但我不知道这是否会让你的生活变得更轻松或更困难,因为你需要这些代码。但这一改变将修正悬赏评论中的三点。更改非常简单-将
lam
的类型更改为
(va->reprvb)->reprv(a->b)
;对于不绑定变量的类型,
repr
变为
repr v
;您需要
var::va->repr va
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