标签追踪

异常追踪是 effect system “Effect 系统”的一部分。抛出异常是一个 effect 。当然可以定义其他 effect 。自定义 effect 是一种给例程打 标签 并做检查的方法:

  1. type IO = object ## 输入/输出 effect
  2. proc readLine(): string {.tags: [IO].} = discard
  3. proc no_effects_please() {.tags: [].} =
  4. # 编译器禁止这么做:
  5. let x = readLine()

标签必须是类型名称。同 raises 列表一样,tags 列表也可以附加到过程类型上。这会影响类型的兼容性。

标签追踪的推断规则与异常追踪的推断规则类型类似。

有一种禁止某些 effect 出现的方法:

  1. type IO = object ## input/output effect
  2. proc readLine(): string {.tags: [IO].} = discard
  3. proc echoLine(): void = discard
  4. proc no_IO_please() {.forbids: [IO].} =
  5. # 这是可以的,因为它没有定义任何标签:
  6. echoLine()
  7. # 编译器会阻止这种情况:
  8. let y = readLine()

forbids 编译指示定义了一个被禁止的 effect 的列表 —— 如果任何语句具有这些 effect,则编译会失败。 带有 effect 禁止列表的过程类型是不带这种列表的过程类型的子类型:

  1. type MyEffect = object
  2. type ProcType1 = proc (i: int): void {.forbids: [MyEffect].}
  3. type ProcType2 = proc (i: int): void
  4. proc caller1(p: ProcType1): void = p(1)
  5. proc caller2(p: ProcType2): void = p(1)
  6. proc effectful(i: int): void {.tags: [MyEffect].} = echo $i
  7. proc effectless(i: int): void {.forbids: [MyEffect].} = echo $i
  8. proc toBeCalled1(i: int): void = effectful(i)
  9. proc toBeCalled2(i: int): void = effectless(i)
  10. ## 这将会失败,因为toBeCalled1使用了ProcType1所禁止的MyEffect:
  11. caller1(toBeCalled1)
  12. ## 这是可以的,因为toBeCalled2和ProcType1有相同的限制:
  13. caller1(toBeCalled2)
  14. ## 这些都是可以的,因为ProcType2没有副作用限制:
  15. caller2(toBeCalled1)
  16. caller2(toBeCalled2)

ProcType2 是 ProcType1 的子类型。与 tags 编译指示所不同的是,父上下文将:调用具有禁用副作用的其他函数的函数;不继承禁用副作用列表。