Skip to content

Instantly share code, notes, and snippets.

@rgrempel
Created June 30, 2016 22:41
Show Gist options
  • Save rgrempel/f9f60dfbb750e24d1d525562957b8d09 to your computer and use it in GitHub Desktop.
Save rgrempel/f9f60dfbb750e24d1d525562957b8d09 to your computer and use it in GitHub Desktop.
Alternative approach to effect types in Purescript
module Control.Monad.Eff.Alt where
import Control.Bind (bind)
import Control.Monad.Eff.Exception (Error)
import Partial.Unsafe (unsafeCrashWith)
import Prelude (liftA1, class Functor, class Applicative, class Monad, ap, class Apply, class Bind, class Show, Unit)
-- This illustrates an alternative way to use the type system to model
-- effects, where the effects type is a "regular" type, and the effects
-- themselves are type-classes. In effect, the effects type is then
-- a set of type-classes, which matches what the type system does ...
-- that is, a type can implement a set of type-classes.
--
-- I've taken some examples from "Purescript by Example" and illustrated
-- how it might look.
-- | The `Eff` type constructor is used to represent _native_ effects.
-- |
-- | The first type parameter is a type which implements type-classes which
-- | represent the contexts in which a computation can be run, and the second type
-- | parameter is the return type.
foreign import data Eff :: * -> * -> *
-- Consider
--
-- forall eff1. Eff (random :: RANDOM | eff1) Number
--
-- This would now be:
class RANDOM e
random :: forall eff1. (RANDOM eff1) => Eff eff1 Number
random = unsafeCrashWith "Unimplemented"
-- Now, consider
--
-- forall eff2. (Show a) => a -> Eff (console :: CONSOLE | eff2) Unit
--
-- This would now be:
class CONSOLE e
print :: forall a eff2. (Show a, CONSOLE eff2) => a -> Eff eff2 Unit
print = unsafeCrashWith "Unimplemented"
-- Then, main might be typed like this
main :: forall eff. (CONSOLE eff, RANDOM eff) => Eff eff Unit
main = do
n <- random
print n
-- Or, if you want to restrict the effects, then like this, which
-- (correctly) refuses to compile, if you un-comment the signature.
--
-- main2 :: forall eff. (CONSOLE eff) => Eff eff Unit
main2 = do
n <- random
print n
-- If you leave the signature commented, the compiler (correctly) infers:
--
-- forall t6. (RANDOM t6, CONSOLE t6) => Eff t6 Unit
-- Now, what about handlers, that subtract effects?
--
-- So, if we start with this:
class EXCEPTION e
throwException :: forall a eff. (EXCEPTION eff) => Error -> Eff eff a
throwException = unsafeCrashWith "Unimplemented"
-- Then the handler would look like this:
catchException :: forall a eff1 eff2. (EXCEPTION eff1) =>
(Error -> Eff eff2 a) ->
Eff eff1 a ->
Eff eff2 a
catchException = unsafeCrashWith "Unimplemented"
-- One flaw (possibly fatal) is how do you assert the *absence* of an effect type?
-- You kind of need to do this for the `runPure` style of function.
-- The instances are fake, just so the type checker sees what it expects for Eff
instance functorEff :: Functor (Eff e) where
map = liftA1
instance applyEff :: Apply (Eff e) where
apply = ap
instance applicativeEff :: Applicative (Eff e) where
pure = unsafeCrashWith "unimplemneted"
instance bindEff :: Bind (Eff e) where
bind = unsafeCrashWith "unimplemented"
instance monadEff :: Monad (Eff e)
@rgrempel
Copy link
Author

rgrempel commented Jul 1, 2016

Just as a note to myself, it's possible that some kind of type-level operator for asserting the absence of a type-class might fit well with "Constraint Kinds", which are on the roadmap for Purescript at some point. (That is, one might imagine an assertion of the absence of constraints, or a particular constraint, as being a constraint kind, just as the assertion of the presence of a constraint is).

The other thing I looked at briefly is the idea of "extensible effects" as implemented in the extensible-effects Haskell library. In the Haskell context, this is more of an alternative to monad transformers than it is an approach to FFI. However, there may be some conceptual similarity there at some level.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment