Typeclass instance with row type in instance head?
While I was playing with PureScript, I found that I wanted to write a typeclass Sync
that would wait for arbitrary asynchronous values to resolve in the Aff
monad. The typeclass I wrote looked like this:
class Sync s eff a where
sync :: s -> Aff eff a
Now I wanted to create Sync
instance for a websocket connection, which would wait until the connection was open and available for reading/writing. The instance I wrote looked like this:
instance syncConnection :: Sync Connection (ws :: WEBSOCKET | eff) Unit where
sync (Connection socket) =
makeAff $ fail continue ->
set socket.onopen $ _ ->
continue unit
However, I got the following type error:
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.
Coming from Haskell, this makes sense to me—it mirrors situations where I would need to enable the FlexibleInstances
extension, which PureScript does not seem to support, either—but I'm left wondering if I can achieve the genericism I want at all.
I thought that perhaps I could tweak my Sync
class, then just create a newtype.
class Sync s m a where
sync :: s -> m a
newtype WebSocketAff a = WebSocketAff (Aff (ws :: WEBSOCKET) a)
Unfortunately, now I'm stuck yet again because I don't know of any way to give WebSocketAff
an instance of MonadAff
for similar reasons to the ones I encountered at the beginning.
Are there any tricks I could use to get this to work without defeating the purpose of the genericism entirely? Or is that sort of thing currently not really expressible within PureScript?
Since compiler version 0.10.3 you are allowed to use rows in the instance head as long as the row is determined via a FunDep:
eg
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
Release Notes v0.10.3: https://github.com/purescript/purescript/releases/tag/v0.10.3
我在我的移动ATM上,所以我无法测试这个,但是您是否尝试使用forall?
instance syncConnection :: forall eff. Sync Connectionync Connection . . .
上一篇: 约束约束的论点