如何在Haskell中实现所有图形和Web库?

时间:2013-04-05 13:15:47

标签: haskell functional-programming monads hackage

我才开始学习Haskell。我读过它是一种纯函数式语言,其中的所有内容都是不可变的。因此输入输出,写入和读取数据库之类的东西会导致状态的可变性。我知道Haskell中有一个名为monads的东西允许在Haskell中使用命令式功能,如IO Monad。但我很有意思的是Haskell的一切必要性是在monads的帮助下实现的吗?在HackageDB上有很多软件包可以使用3d图形,数据库,解析HTML,编写Web服务器等等。

这一切背后的一般理念是什么?是什么让Haskell保持纯粹并同时适用于写这一切?我希望有人能为我说清楚。提前谢谢!

4 个答案:

答案 0 :(得分:12)

我使用以下类比来理解这些内容,我将用JavaScript表达。

如何表达副作用计算?

1。功能

这显然是首先想到的事情:

var launchRockets = function () {
  prepareRockets( queryDBForPreparationParameters() )
  launchAllPreparedRockets()
  outputResults()
}

你可以看到一个有效的函数调用一堆其他有效的函数,这些函数本身可以产生未知的效果,带来所有后续的后果。

2。说明

另一种表达方式的方法是编写一组指令,描述某些函数的有效计算以便以后执行。 (曾经编写过SQL查询吗?)

var launchRocketsInstructions = [
  {
    description: "Prepare rockets",
    parameters: {
      description: "Query a DB for preparation parameters"
    }
  },
  {
    description: "Launch all prepared rockets"
  },
  {
    description: "Output results"
  }
]

那么我们在第二个例子中看到了什么?我们看到一个描述计算的不可变数据树,而不是立即执行它。这里没有副作用,为了组成这个数据树,我们肯定可以使用纯函数。这就是Haskell的基本副作用。语言提供的所有基础结构:monad,IOdo - 符号 - 这些只是工具和抽象,简化了编写单个指令树的任务。

当然,为了实际执行这些指令,人们最终必须逃离到副作用的狂野世界。在JavaScript的情况下,它将类似execute(launchRocketsInstructions),在Haskell的情况下,它是运行时执行指令树的根的运行时,您使用主模块的函数main生成指令树的根,这将成为单个你的计划的切入点。因此,Haskell中的副作用实际上发生在语言范围之外,这就是为什么它是纯粹的。

答案 1 :(得分:8)

  

我读过它是一种纯函数式语言,其中的所有内容都是不可变的。

Haskell只是纯/默认/。如果你向编译器声明(通过monadic类型)你想要有某些效果,那么它们就被启用了。

默认情况下它们没有打开。

答案 2 :(得分:3)

在Haskell中,你从未真正执行过任何事情。您只需通过组合IO操作建立对您希望执行的操作的描述,然后将该描述分配给main。然后,编译器将它在主变量中找到的任何程序描述转换为可执行代码。

我建议你阅读这篇introduction to Haskell IO我写的更详细的解释。

但是,这只能说明我们如何组合IO操作而不是如何引入新操作。 Haskell有两种方法可以添加新的IO操作:

  • 编译器内置插件
  • 外部函数接口(FFI)

然后,所有IO monad都将这些原始IO动作组合成更大的IO动作。

答案 3 :(得分:0)

是的,Haskell中的所有必要条件都是在monad的帮助下编写的。 Monads是一般的想法,它允许Haskell既纯粹又适用于编写实际I / O的实用程序。

我建议阅读Simon Peyton Jones撰写的着名论文"Tackling the Awkward Squad",其中解释了如何使用IO monad以纯函数语言进行实际编程。