haskell - Typed Tagless Final Interpreters: what is the use of duplicate?
问题描述
This question is related to the paper Typed Tagless Final Interpreters. In page 11, a function trice
is presented, which relies on a duplicate
function:
I've tried coding this into Haskell, and the resulting functions look as follows:
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
However, since I cannot seem to be able to give a more generic type to thrice
I could have just written the simpler function:
thrice' :: (Int, (String, Tree)) -> IO ()
thrice' (reprInt, (reprStr, reprTree)) = do
print $ eval reprInt
print $ view reprStr
print $ toTree reprTree
So I was wondering what is the use of duplicate
in this example?
解决方案
首先,顺便说一句,请注意那篇文章中的代码已经是有效的 Haskell 代码,只是使用了一些符号代替了通常的 Haskell 语法。例如,符号“◦”用于代替(.)
运算符来进行功能组合。
因此,您可以thrice
直接根据文章中的定义编写以下有效的 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_consume
为上面的版本,或者duplicate
完全删除并编写:
dup_consume ev x = print (ev x1) >> return x2
where (x1, x2) = x
而且,当然,您可以将定义dup_consume
直接合并到 中thrice
,就像您所做的那样。
但是,文章中的所有最终“解释器”都没有真正的目的。这就是重点。特别是,您不需要eval
或view
定义thrice
任何一个。以下工作也很好:
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
函数——强制返回值是一个整数,这反过来又会选择正确的实例来评估最终表达式,而不是view
ing 它或其他东西。但你也可以写:
> neg (lit 1) :: Int
-1
>
以获得相同的效果。
事实证明,这duplicate
比其他解释器更不需要,因为在唯一使用它的地方——即定义dup_consume
:
dup_consume ev x = print (ev x1) >> return x2
where (x1, x2) = duplicate x
类型检查器已经可以推断出需要一个元组,因此为 提供的任何最终表达式x
,likeneg (lit 1)
必然会被解释为元组的重复实例(即,在定义之前定义的实例duplicate
),所以 - 如上所述-- 你可以写:
dup_consume ev x = print (ev x1) >> return x2
where (x1, x2) = x
类型检查器会弄清楚的。
推荐阅读
- python - 橙色 - 通过基于列值创建新行来重写数据
- r - 从 R 中的嵌套数据框中提取值
- drop-down-menu - 带有图标的 React-bootstrap 自定义下拉按钮
- git - 我在哪里可以找到 VS Code 中的遥控器 url
- reactjs - 部署到 heroku path="/" path="/favicon.ico" 的问题
- android - RecyclerView 滚动条未触及视图底部
- javascript - React Native 获取和渲染 json
- django - Django-如何使用从一个模型到另一个模型的一个字段?
- javascript - 有没有办法在不分页的情况下使用 jqGrid 加载大数据
- laravel - 具有自定义登录的 Laravel 5.4 无法重定向