Экземпляр Typeclass с типом строки в заголовке экземпляра?

Играя с PureScript, я обнаружил, что хочу написать класс типов Sync, который будет ждать разрешения произвольных асинхронных значений в монаде Aff. Написанный мной класс типов выглядел так:

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

Теперь я хотел создать Sync экземпляр для соединения через веб-сокет, который будет ждать, пока соединение не будет открыто и доступно для чтения / записи. Написанный мною экземпляр выглядел так:

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 Sync s m a where
  sync :: s -> m a

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

К сожалению, сейчас я снова застрял, потому что не знаю способа дать WebSocketAff экземпляр MonadAff по причинам, аналогичным тем, с которыми я столкнулся в начале.

Есть ли какие-нибудь уловки, которые я мог бы использовать, чтобы заставить это работать, не уничтожая полностью цель дженеризма? Или такие вещи в настоящее время невозможно выразить в PureScript?


person Alexis King    schedule 14.05.2016    source источник


Ответы (2)


Начиная с версии компилятора 0.10.3, вам разрешено использовать строки в заголовке экземпляра, если строка определяется с помощью FunDep:

e.g.

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

person pete    schedule 13.12.2016
comment
Вау, спасибо, что ответили на этот старый вопрос, это действительно здорово узнать об этом. Когда я писал этот вопрос, PS даже не поддерживал функциональные зависимости, но это полностью решает мой вариант использования. Захватывающе! - person Alexis King; 14.12.2016

Я использую мобильный банкомат, поэтому я не могу это проверить, но вы пробовали использовать его для всех?

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

person clinux    schedule 31.05.2016
comment
Да; это не только не сработало, но и, похоже, было ошибкой парсера. - person Alexis King; 01.06.2016