关于模板哈斯克尔有什么不好? [英] What's so bad about Template Haskell?

查看:66
本文介绍了关于模板哈斯克尔有什么不好?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Haskell社区经常将Haskell看作是一种不幸的方便。在这方面,我很难将语言完全融入到语言中,但考虑一下这些例子



我看过各种博客文章,其中人们用Template Haskell做了非常整洁的事情,使得更漂亮的语法在普通的Haskell中是不可能的升降低了巨大的样板。那么为什么模板哈斯克尔被这样看待呢?什么使它不受欢迎?在什么情况下应该避免模板哈斯克尔,为什么?解析方案

避免模板哈斯克尔的一个原因是,它作为一个整体isn根本不符合类型安全,因此违背了Haskell的精神。这里有一些这样的例子:


  • 你无法控制TH代码将生成哪种类型的Haskell AST,除此之外会出现;你可以有一个类型值 Exp ,但是您不知道它是否是表示 [Char] (a - >(forall b。b - > c))或其他。如果可以表示一个函数只能生成某种类型的表达式,或者只是函数声明,或者只有数据构造函数匹配模式等,那么TH会更可靠。

  • 生成不能编译的表达式。您是否生成了一个引用了不存在的自由变量 foo 的表达式?运气不好,只有在实际使用代码生成器时才会看到,只有在触发生成特定代码的情况下。单元测试也很难。


    TH也是非常危险的:


    • 在编译时运行的代码可以执行任意 IO ,包括启动导弹或窃取信用卡。你不需要仔细查看你曾经下载过的任何一个搜索TH漏洞的软件包。

    • TH可以访问模块专用函数和定义,完全破解某些封装



    然后出现一些问题,使TH功能作为图书馆开发人员变得不那么有趣:




    • TH代码不总是可组合的。比方说,有人为镜头制造发电机,而且往往不是,发电机的构造方式只能由最终用户直接调用,而不能由其他TH代码调用,例如采用生成透镜作为参数的类型构造函数列表。在代码中生成该列表非常棘手,而用户只需编写 generateLenses [''Foo,'Bar'

    • 开发人员甚至不知道可以组成TH代码的 。你知道你可以写 forM_ [''Foo,'Bar'generateLens Q 只是一个单子,所以你可以使用它上面的所有常用功能。有些人不知道这一点,因此,他们创建了多个具有相同功能的基本相同功能的重载版本,这些功能导致了一定的膨胀效应。另外,大多数人在 Q monad中编写他们的生成器,即使他们不需要,就像写 bla :: IO Int; bla = return 3 ;你正在给一个比它需要更多环境的函数,并且这个函数的客户端需要提供那个环境作为它的一个效果。



    最后,有些东西使TH功能作为最终用户使用起来不那么有趣:


    • 不透明度。当一个TH函数的类型为 Q Dec 时,它可以在模块的顶层生成绝对的任何东西,并且完全不能控制生成的东西。

    • Monolithism。除非开发人员允许,否则无法控制TH函数的产生量;如果您发现一个生成数据库接口的JSON序列化接口的函数,则不能说不,我只想要数据库接口,谢谢;我会推出我自己的JSON接口 / li>
    • 运行时间。 TH代码需要相当长的时间才能运行。每次编译文件时都会重新解释代码,并且通常,运行的TH代码需要大量的包,这些包必须加载。这大大减慢了编译时间。


    It seems that Template Haskell is often viewed by the Haskell community as an unfortunate convenience. It's hard to put into words exactly what I have observed in this regard, but consider these few examples

    I've seen various blog posts where people do pretty neat stuff with Template Haskell, enabling prettier syntax that simply wouldn't be possible in regular Haskell, as well as tremendous boilerplate reduction. So why is it that Template Haskell is looked down upon in this way? What makes it undesirable? Under what circumstances should Template Haskell be avoided, and why?

    解决方案

    One reason for avoiding Template Haskell is that it as a whole isn't type-safe, at all, thus going against much of "the spirit of Haskell." Here are some examples of this:

    • You have no control over what kind of Haskell AST a piece of TH code will generate, beyond where it will appear; you can have a value of type Exp, but you don't know if it is an expression that represents a [Char] or a (a -> (forall b . b -> c)) or whatever. TH would be more reliable if one could express that a function may only generate expressions of a certain type, or only function declarations, or only data-constructor-matching patterns, etc.
    • You can generate expressions that don't compile. You generated an expression that references a free variable foo that doesn't exist? Tough luck, you'll only see that when actually using your code generator, and only under the circumstances that trigger the generation of that particular code. It is very difficult to unit test, too.

    TH is also outright dangerous:

    • Code that runs at compile-time can do arbitrary IO, including launching missiles or stealing your credit card. You don't want to have to look through every cabal package you ever download in search for TH exploits.
    • TH can access "module-private" functions and definitions, completely breaking encapsulation in some cases.

    Then there are some problems that make TH functions less fun to use as a library developer:

    • TH code isn't always composable. Let's say someone makes a generator for lenses, and more often than not, that generator will be structured in such a way that it can only be called directly by the "end-user," and not by other TH code, by for example taking a list of type constructors to generate lenses for as the parameter. It is tricky to generate that list in code, while the user only has to write generateLenses [''Foo, ''Bar].
    • Developers don't even know that TH code can be composed. Did you know that you can write forM_ [''Foo, ''Bar] generateLens? Q is just a monad, so you can use all of the usual functions on it. Some people don't know this, and because of that, they create multiple overloaded versions of essentially the same functions with the same functionality, and these functions lead to a certain bloat effect. Also, most people write their generators in the Q monad even when they don't have to, which is like writing bla :: IO Int; bla = return 3; you are giving a function more "environment" than it needs, and clients of the function are required to provide that environment as an effect of that.

    Finally, there are some things that make TH functions less fun to use as an end-user:

    • Opacity. When a TH function has type Q Dec, it can generate absolutely anything at the top-level of a module, and you have absolutely no control over what will be generated.
    • Monolithism. You can't control how much a TH function generates unless the developer allows it; if you find a function that generates a database interface and a JSON serialization interface, you can't say "No, I only want the database interface, thanks; I'll roll my own JSON interface"
    • Run time. TH code takes a relatively long time to run. The code is interpreted anew every time a file is compiled, and often, a ton of packages are required by the running TH code, that have to be loaded. This slows down compile time considerably.

    这篇关于关于模板哈斯克尔有什么不好?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆