Module

EffObject

Package
purescript-eff-object
Repository
hdgarrood/purescript-eff-object

This module contains declarations and some basic functions to allow you to give PureScript types to stateful or otherwise effectful JavaScript APIs like XMLHttpRequest or WebSocket without writing a ton of error-prone and tedious FFI code.

For example, if you wanted to provide a low-level typing for the XMLHttpRequest web API, you might write the following:

type XMLHttpRequest e =
  EffObject
    -- The first type argument contains effects associated with interacting
    -- with the object. Interacting with an XHR uses an AJAX effect, so
    -- we record this here.
    ( ajax :: AJAX )
    -- We record the properties as well as their types and access levels
    -- in the second type argument.
    ( onreadystatechange :: ReadWrite (Eff e Unit)
    , readyState :: ReadOnly Int
    , response :: ReadOnly (Nullable Response)
    , [...]
    )

Consumers of your API can now interact with an XMLHttpRequest object using the readProperty or writeProperty functions:

checkReadyState ::
  forall e.
  XMLHttpRequest e ->
  Eff (ajax :: AJAX | e) String
checkReadyState req = do
  s <- readProperty (SProxy :: SProxy "readyState") req
  pure $ if (s == done)
    then "Done!"
    else "Not done."
  where
    done = 4

Attempting to write read-only properties will produce a custom type error explaining what happened:

oops :: forall e. XMLHttpRequest e -> Eff (ajax :: AJAX | e) Unit
oops req = writeProperty (SProxy :: SProxy "readyState") req 0
-- Throws:
--   A custom type error occurred while solving type class constraints:
--     Cannot write to a read-only property.

Note that any APIs constructed using this library will necessarily be very low-level; you might want to build extra layers above this API, for instance, to provide a real ReadyState type which is guaranteed to only take values which would be valid the for readyState property itself.

#ReadOnly Source

data ReadOnly (a :: Type)

Instances

#WriteOnly Source

data WriteOnly (a :: Type)

Instances

#Readable Source

class Readable (a :: Type -> Type) 

Instances

#Writeable Source

class Writeable (a :: Type -> Type) 

Instances

#EffObject Source

data EffObject (e :: Row Effect) (props :: Row Type)

A JavaScript object, with properties which can be read or written. The type arguments track:

  • e: Effects associated with reading or writing properties
  • props: Properties.

The labels in the props row type must correspond exactly to the property names on the underlying object, and the types in the props row should be of the form ReadOnly a, WriteOnly a, or ReadWrite a, depending on the access level, and where a is the type of the property's value.

#readProperty Source

readProperty :: forall a access name props' props prop e. IsSymbol name => Readable access => RowCons name prop props' props => TypeEquals prop (access a) => SProxy name -> EffObject e props -> Eff e a

Read a property from an EffObject.

#writeProperty Source

writeProperty :: forall a access name props' props prop e. IsSymbol name => Writeable access => RowCons name prop props' props => TypeEquals prop (access a) => SProxy name -> EffObject e props -> a -> Eff e Unit

Write a property to an EffObject.

#BoundFunction Source

newtype BoundFunction (receiver :: Type) (fn :: Type)

A function which should be called with a this value which is a specific type. The fn type argument should generally either be an EffFn from purescript-eff, or a Fn from purescript-functions.

#mkBoundFunction Source

mkBoundFunction :: forall receiver fn. fn -> BoundFunction receiver fn

Wrap a function in a BoundFunction constructor to ensure that it may only be called with a this value of the type receiver.

#bindTo Source

bindTo :: forall receiver fn. receiver -> BoundFunction receiver fn -> fn

Run a BoundFunction by providing a this object.

#Self Source

data Self

This type provides a way of saying that a BoundFunction which is a property of some EffObject should receive that EffObject as its this value when called.

#BoundMethod Source

#bindProperty Source

bindProperty :: forall fn access name props' props prop e. IsSymbol name => Readable access => RowCons name prop props' props => TypeEquals prop (access (BoundMethod fn)) => SProxy name -> EffObject e props -> Eff e fn
Modules
EffObject