Haskell 打字无标记最终口译:复制有什么用?
这个问题与论文有关。在第11页中,介绍了一个函数Haskell 打字无标记最终口译:复制有什么用?,haskell,interpreter,Haskell,Interpreter,这个问题与论文有关。在第11页中,介绍了一个函数trice,该函数依赖于一个复制函数: thrice' :: (Int, (String, Tree)) -> IO () thrice' (reprInt, (reprStr, reprTree)) = do print $ eval reprInt print $ view reprStr print $ toTree reprTree 我尝试将其编码到Haskell中,结果函数如下所示: thrice
trice
,该函数依赖于一个复制
函数:
thrice' :: (Int, (String, Tree)) -> IO ()
thrice' (reprInt, (reprStr, reprTree)) = do
print $ eval reprInt
print $ view reprStr
print $ toTree reprTree
我尝试将其编码到Haskell中,结果函数如下所示:
thrice :: (Int, (String, Tree)) -> IO () -- Is this the most generic type we can give?
thrice x0 = do
x1 <- dupConsume eval x0
x2 <- dupConsume view x1
print $ toTree x2
where
dupConsume ev y = do
print (ev y0)
return y1
where
(y0, y1) = duplicate y
所以我想知道在这个例子中,
duplicate
有什么用?首先,作为旁白,请注意,那篇文章中的代码已经是有效的Haskell代码,只是使用了一些符号来代替通常的Haskell语法。例如,符号“◦" 用于代替函数合成的(.)
运算符
因此,您可以直接根据本文中的定义,将编写三次作为以下有效的Haskell代码:
thrice x = dup_consume eval x >>= dup_consume view
>>= print . toTree
dup_consume ev x = print (ev x1) >> return x2
where (x1, x2) = duplicate x
无论如何,回到你的问题上来……正如你正确指出的那样,解释器duplicate
没有真正的用途。例如,你可以将dup\u consume
定义为上面的版本,或者完全删除duplicate
,然后写下:
dup_consume ev x = print (ev x1) >> return x2
where (x1, x2) = x
当然,您可以将dup\u consume
的定义直接合并为三次
,就像您所做的那样
然而,本文中所有的最终“解释者”都没有真正的目的。这就是重点。特别是,你不需要eval
或view
来定义三次
thrice' :: (Int, (String, Tree)) -> IO ()
thrice' (reprInt, (reprStr, reprTree)) = do
print $ reprInt
print $ reprStr
print $ reprTree
之后,您可以执行以下操作:
> thrice' (add (lit 5) (neg (lit 2)))
3
"(5 + (-2))"
Node "Add" [Node "Lit" [Leaf "5"],Node "Neg" [Node "Lit" [Leaf "2"]]]
>
这些最终口译员的想法是打字决定口译。口译员的目的只是添加没有明确类型签名的打字信息。因此,eval(neg(lit 1))
可以在GHCi提示符下输入,而不需要类型签名:
> eval (neg (lit 1))
-1
>
它之所以“起作用”,是因为eval
——这只是id
函数——强制返回值为整数,这反过来又选择正确的实例来计算最终表达式,而不是查看它或其他什么。但您也可以编写:
> neg (lit 1) :: Int
-1
>
为了得到同样的效果
事实证明,duplicate
比其他口译员更不必要,因为在唯一使用它的地方,即dup\u consume
的定义:
dup_consume ev x = print (ev x1) >> return x2
where (x1, x2) = duplicate x
类型检查器已经可以推断需要一个元组,因此为x
提供的任何最终表达式,如neg(lit 1)
,都必须被解释为元组的复制实例(即,在定义replicate
之前定义的实例),因此如上所述,您可以编写:
dup_consume ev x = print (ev x1) >> return x2
where (x1, x2) = x
类型检查器会找到答案。我可能错了,但我怀疑您的三次
函数可能涉及多次解析表达式,而Oleg的复制
技巧只会复制解析树(即解析结果)
重复的需要源于对解析结果的模式匹配,它为匹配的解析结果分配了一个单态类型。因此,一旦你为它选择了一个解释器,你就会被它卡住。论文提到了一种更高的秩编码,以牺牲可扩展性来回收这种丢失的多态性,这违背了f无标记的最终口译员
另一种方法是replicate
技巧,它将(单态)解析结果复制到另一个(单态)值中,以进行不同的解释
当然,如果解析始终成功(例如,通过直接在解析树中编码解析错误)这样就不需要重复了,因为解析结果可以保持多态性,并且可以进行不同的解释。请不要嵌入文本图像。将文本复制为文本。感谢您的反馈。是否有任何原因说明嵌入图像不方便?嵌入图像对于使用屏幕阅读器或盲文显示的人来说是无用的是的。用移动浏览器很难阅读。而且也没有希望在浏览器中搜索文本。所以不要这样做。另外,我怀疑对于不容易支持多态值(如Rust)的语言,也需要使用replicate
技巧。