实例头中具有行类型的类型类实例?

Typeclass instance with row type in instance head?

当我在玩 PureScript 时,我发现我想写一个类型class Sync 来等待任意异步值在 Aff monad 中解析。我写的类型class是这样的:

class Sync s eff a where
  sync :: s -> Aff eff a

现在我想为 websocket 连接创建 Sync 实例,它将等待连接打开并可用于 reading/writing。我写的实例是这样的:

instance syncConnection :: Sync Connection (ws :: WEBSOCKET | eff) Unit where
  sync (Connection socket) =
    makeAff $ \fail continue ->
      set socket.onopen $ \_ ->
        continue unit

但是,我收到以下类型错误:

Type class instance head is invalid due to use of type

  ( ws :: WEBSOCKET
  | eff
  )

All types appearing in instance declarations must be of the form T a_1 .. a_n, where each type a_i is of the same form.

来自 Haskell,这对我来说很有意义 — 它反映了我需要启用 FlexibleInstances 扩展的情况,而 PureScript 似乎也不支持 — 但我想知道我是否可以实现我想要的通用性。

我想也许我可以调整我的 Sync class,然后创建一个新类型。

class Sync s m a where
  sync :: s -> m a

newtype WebSocketAff a = WebSocketAff (Aff (ws :: WEBSOCKET) a)

不幸的是,现在我又被困住了,因为我不知道有什么方法可以给 WebSocketAff 一个 MonadAff 的实例,原因与我一开始遇到的类似。

有没有什么技巧可以让我在不完全违背通用主义目的的情况下让它发挥作用?还是目前在 PureScript 中无法真正表达这种东西?

我在移动 ATM 上,所以我无法对此进行测试,但您尝试过使用 forall 吗?

instance syncConnection :: forall eff. Sync Connectionync Connection . . .

从编译器版本 0.10.3 开始,您可以在实例头中使用行,只要该行是通过 FunDep 确定的:

例如

class Sync s eff a | s -> eff where -- FunDep here: eff is determinded via s
  sync :: s -> Eff eff a

data ConsoleSync = ConsoleSync

instance syncWithConsole :: Sync ConsoleSync (console :: CONSOLE | eff) Unit where
  sync _ = log "hello"

foo :: ∀ eff. Eff (console :: CONSOLE | eff) Unit
foo = sync ConsoleSync

发行说明 v0.10.3:https://github.com/purescript/purescript/releases/tag/v0.10.3