如何在整个web应用程序堆栈中利用Haskell类型的安全性

How can you leverage Haskell type safety through the whole web application stack?

本文关键字:Haskell 类型 安全性 堆栈 应用程序 web      更新时间:2023-09-26

我想知道以CRUD为中心的web应用程序能从Haskell的类型系统中受益多少,尤其是当前端使用像AngularJS这样的Javascript MVC框架构建时,该框架传递无类型的数据对象。

在我看来,一旦您将Haskell数据类型转换为JSON对象,并将其传递给一个沉重的JavaScriptMVC框架层,那么将Haskell's类型系统作为web堆栈的一部分的好处就会开始显著削弱,因为没有办法让类型检查器确保整个web应用程序中数据流的类型完整性。

例如,您可以更改数据库模式和相关的Haskell类型,但类型检查器无法告诉您JavaScriptMVC前端的哪些部分也需要更新。我认为这是个问题。

我是否正确地陈述了这个问题?如果是,Haskell web应用程序开发人员在这一点上可以给出什么建议?

自从我们最近开始了一个使用大量javascript前端的项目以来,我们一直在努力解决这个完全相同的问题。我的轶事观察是,与之前使用Snap并使用Heist生成HTML的应用程序相比,javascript应用程序中的错误要多得多。我们还没有决定任何事情,但以下是我们一直在考虑的一些可能的解决方案:

精简Javascript包装器

  • CoffeeScript
  • TypeScript
  • Dart

这些解决方案对我来说非常不满意。在Javascript上有了一些改进,但并没有给我带来Haskell带来的东西。

更具功能性和类型安全性的前端语言

  • Fay是Haskell的一个子集,可以编译成Javascript。它确实有一些吸引力,但并不能让你访问所有的Haskell。上次我听说它不支持类型类,我想这很快就会成为一个障碍
  • Elm
  • 罗伊

这些解决方案(以及前一组)的问题是,如果您的后端是用Haskell编写的,那么您仍然存在阻抗不匹配,因为您的前端语言不是Haskell。这使得您的代码不那么枯燥,因为您最终必须在Haskell和前端语言中定义相同的数据结构。当您在Haskell中更改它们时,不会出现指示前端代码需要更改的位置的错误。应用程序刚坏。

将Haskell编译为Javascript

城里的新游戏是ghcjs。这是一个非常有前景的项目,但我认为它至少在GHC7.8发布之前是不可行的。这有望在下周内实现。一旦7.8问世,你仍然需要考虑到ghcjs仍然是非常新的。即使在假设它100%完成了功能并且第一个版本运行良好的情况下,你仍然必须记住,在Haskell+ghcjs像Angular、Ember等高级javascript框架一样有效之前,还必须构建相当多的基础设施。

2016年9月更新:现在,在我最初写下这个答案近三年后,GHCJS有了很大的改进。还有更多改进的空间,但我已经将其用于生产应用程序,效果非常好。当与Reflex FRP库相结合时,它的功能尤其强大,这使得构建反应UI变得更加容易。

使用EDSL从Haskell生成Javascript

如果您有一个相对受限的问题,那么可能在生成javascript的EDSL上完成所有应用程序工作。我们已经有了出色的jmacro包来处理生成Javascript的低级别问题。您可以利用这一点,生成使用适合您的应用程序的任何其他javascript库的代码。这可以是javascript+jquery、D3.js,甚至可以是使用Angular或Ember等更高级别javascript框架的代码。我倾向于认为Angular比Ember更容易生成代码,因为它简单且封装性更强。

Greenfield是为浏览器中的函数语言设计的字节码虚拟机

这只是我的一个不切实际的想法。我认为这并不实际,因为这需要大量的工作,而且很难被采用。但我至少想提一下完整性的想法。其他人指出,asm.js几乎已经是这样了。可能是这样,但从一开始就将尾调用优化之类的东西设计到VM级别会很好。

在我看来,简单的解决方案-从haskell数据声明(或其他api方案描述)生成typescript接口,并将typescript用于前端部分。它为那些不了解haskell但了解Javascript的人提供了从事项目的机会。

例如

data RpcResponse = RpcResponse { number :: Int, string :: Maybe String }

编译为

interface RpcResponse {
  number : number,
  string?: string
}

函数parseRpcResponseJson具有Typescript类型

parseRpcResponseJson(response: string): Option<RpcResponse>;