clinux
clinux

Reputation: 3074

Polymorphic instruction in Free Monad in Purescript

I'm trying to get this small piece of code to compile.

module Sodium where

import Prelude
import Control.Monad.Free
import Data.Coyoneda
import Data.Tuple

data ReactiveF more
  = RFNewEvent (forall a. (Tuple (Event a) (a -> Reactive Unit) -> more))

type Reactive a = FreeC ReactiveF a

data Event a = Event a

newEvent :: forall a. Reactive (Tuple (Event a) (a -> Reactive Unit))
newEvent = liftFC $ RFNewEvent id

If I instead use "Number" instead of "a" in RFNewEvent, then everything compiles fine. But the moment I go "forall a." and replace "Number" with "a" it no longer compiles.

I get the following error message

Cannot unify type
  a1
with type
  a0

Does anyone know how to make this work?

I'm using version 0.5.0 of purescript-free.

Edit

If I use the following

data NewEventData = NewEventData forall a. Tuple (Event a) (a -> Reactive Unit)

and substitute it into RFNewEvent, then it will compile. But I end up with an undesired type signature for newEvent.

newEvent :: Reactive NewEventData
newEvent = liftFC $ RFNewEvent id

Which lets me create an event, but lets me shoot different event values to the event stream instead of the same type of value. (missing forall a. now on newEvent)

I might of made a mistake.

The overall goal is to simulate SodiumFRP's interface using a Free Monad. Then plug in an existing JavaScript FRP library that works similar to Sodium via FFI when interpreting the Free Monad.

Is this possible?

Upvotes: 3

Views: 223

Answers (1)

clinux
clinux

Reputation: 3074

The following code now compiles and has the desired type signature for "newEvent"

module FRP.Sodium where

import Prelude
import Control.Monad.Free
import Data.Coyoneda
import Data.Tuple

data ReactiveF more
  = RFNewEvent (NewEventData -> more)

type Reactive a = FreeC ReactiveF a

data NewEventData = NewEventData forall a. Tuple (Event a) (a -> Reactive Unit)

data Event a
  = ENever
  | EMerge (Event a) (Event a)
  | EFilterJust (Event (Maybe a))
  | ECoalesce (a -> a -> a) (Event a)
  | EOnce (Event a)
  | ESplit (Event (Array a))
  | EVar Int

data Behaviour a = BVar Int

extractNewEventData :: forall a. NewEventData -> (Tuple (Event a) (a -> Reactive Unit))
extractNewEventData (NewEventData x) = x

newEvent :: forall a. Reactive (Tuple (Event a) (a -> Reactive Unit))
newEvent = map extractNewEventData $ liftFC $ RFNewEvent id

Edit

Also trying out purescript-exists. Makes it possible to define "sample"

RFSample gets added to ReactiveF ...

.
.
.
data ReactiveF more
  = RFNewEvent (NewEventData -> more)
  | RFSample (SampleData more)
.
.
.
data SampleDataF more a = SampleDataF (Behaviour a) (a -> more)
type SampleData more = Exists (SampleDataF more)

sample :: forall a. Behaviour a -> Reactive a
sample beh = liftFC $ RFSample $ mkExists $ SampleDataF beh id

Thank you Phil Freeman for your comment.

Upvotes: 2

Related Questions