2

要将 IO 函数添加到用 Haskell 编写的编程语言解释器中,我基本上有两种选择:

  • 修改整个解释器以在 IO monad 内部运行
  • 让解释程序可以调用的运行时函数使用unsafePerformIO.

前者对我来说是个坏主意——这实际上抵消了程序中几乎所有地方的任何 纯度优势。IO我目前也ST大量使用,并且必须修改大量程序才能实现这一点,因为我看不到同时使用两者STIO?)。

后者让我感到紧张——正如函数名称所述,它不安全的,但我认为在这种情况下它可能是合理的。特别:

  • 此更改涉及的代码量将非常少。
  • 可以执行 IO 的点已经通过在seq解释表达式求值期间使用 at 控制点来显式排序。
  • 或许更重要的是,IO 操作返回的值只会在代码的解释部分中使用,我可以通过解释器不能使用相同的参数多次调用这一事实来保证引用透明性,因为操作计数器将通过线程整个系统作为同一更改的一部分,并且始终以唯一值传递给将使用unsafePerformIO.

在这种情况下,有充分的理由不使用unsafePerformIO吗?

更新

有人问我为什么要保持口译员的纯洁性。原因有很多,但也许最紧迫的是我打算以后为这种语言构建一个编译器,该语言将包含各种元编程技术,这些技术将要求编译器包含解释器,但我想成为能够保证编译结果的纯度。为此目的,该语言将有一个纯子集,我希望解释器在执行该子集时是纯的。

4

1 回答 1

2

如果我理解正确,您想向IO解释语言(不纯的 primops)添加操作,而解释器本身是纯粹的。

第一个选项是来自解释器的抽象 primops。例如,解释器可以在一些未指定的 monad 中运行,同时注入 priops:

data Primops m = Primops
  { putChar :: Char -> m ()
  , getChar :: m Char
  , ...
  }

interpret :: Monad m => Primops m -> Program -> m ()

IO现在解释器除了关闭的primops列表之外不能执行任何操作。(您可以使用自定义 monad 来实现类似的结果,而不是将 primops 作为参数传递。)

但我认为它过度设计,直到你确切地说出为什么你需要纯解释器。可能你没有?如果您只是想让解释器的纯部分易于测试,那么最好将这些部分提取到单独的纯函数中。这样,顶级入口点将是不纯的,但很小,但所有解释器的逻辑都是可测试的。

于 2016-06-25T11:56:25.263 回答