类型级别的唯一符号值

问题描述

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

在 JS 中,Symbol 经常用于这样的事情。但我希望在不使用 Effect 的情况下,在纯上下文中使用它。

好吧,它甚至可能喜欢访问完全限定的模块名称(这对于任务来说非常独特),但我不确定这在 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的状态,它传递给他们值和当前状态值,并用新的状态值获取Effect,并放入key为标签的状态映射中。

模块的用户

一个模块中:


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”)作为标签,而是使用一些“生成的”唯一值,那就太好了。但任务是应该在纯上下文中在模块的顶层创建工作线程。

解决方法

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

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

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

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

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

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

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

workerTag :: String
workerTag = toString $ unsafePerformEffect genUUID