类型级别的唯一符号值

Unique symbol value on type level

是否可以在类型级别上有某种唯一的符号值,可用于区分(标记)某些记录而不需要提供唯一的字符串值?

在JS中有Symbol经常用于这样的事情。但是我想在纯上下文中不使用 Effect 就拥有它。

好吧,它甚至可能喜欢访问完全限定的模块名称(这对于任务来说是非常独特的),但我不确定这是否真的是 relevant/possible Purescript 上下文中的事情。

示例:

说有一些模块公开了:


type Worker value state = 
  { tag :: String
  , work :: value -> state -> Effect state
  }


makeWorker :: forall value state. Worker value state


performWork :: forall value state. woker -> Worker value state -> value -> Unit

这个模块是用来管理worker的状态的,它传递给worker的值和当前状态值,得到新状态值的Effect,放入state map中,key是tags。

模块的用户:

在一个模块中:


worker = makeWorker { tag: "WorkerOne", work }

-- Then this tagged `worker` is used to performWork:
-- performWork worker "Some value"

在另一个模块中,我们使用带有另一个标签的 worker:

worker = makeWorker { tag: "WorkerTwo", work }

因此,如果不需要提供唯一字符串(“WorkerOne”、“WorkerTwo”)作为标签而是使用一些“生成的”唯一值,那就太好了。但是任务是应该在纯上下文中在模块的顶层创建worker。

PureScript 的语义本身是纯粹的,与这类事情几乎不兼容。相同的表达式总是产生相同的结果。结果可以在较低级别以不同方式表示,但在语言语义中它们是相同的。

这是一个功能,不是错误。根据我的经验,通常情况下,像您这样的要求表明上游某处存在设计缺陷。

此规则的一个例外是 FFI:如果您必须与底层平台交互,则别无选择,只能遵守该平台的规则。我可以举的一个例子是 React,它使用 JavaScript 的隐式对象身份作为区分组件的一种方式。

所以底线是:我敦促您重新考虑该要求。很有可能,您 真的 不需要它。即使您这样做,手动指定的字符串实际上可能比自动生成的字符串更好,因为它们可能会帮助您稍后进行故障排除。

但如果你真的坚持这样做,好消息:你可以作弊! :-)

您可以有效地生成您的 ID,然后将它们包装在 unsafePerformEffect 中,使其在编译器看来是纯净的。例如:

import Effect.Unsafe (unsafePerformEffect)
import Data.UUID (toString, genUUID)

workerTag :: String
workerTag = toString $ unsafePerformEffect genUUID