Coming from Odessa, Ukraine
 
Doing Haskell for 6+ years
Now work for
 
Student counseling through automated text messages
Messaging campaigns are written in an in-house DSL
How do you test them?
You create a simulator!
Have the server and simulator use the same code
| Effect | Simulator | Server | 
|---|---|---|
| Logging | Yes | Yes | 
| Current time | Yes | Yes | 
| SMS send/recv | Yes | Yes | 
| Console I/O | Yes | No | 
| MQ | No | Yes | 
handleMessage 
  :: ( MonadWriter LogEntry m
     , MonadWriter MessageText m
     , MonadState Image m
     , MonadReader Messages m
     , MonadReader Now m
     , MonadReader SQL.Connection m
     , MonadExcept DynamicTypeError m
     , MonadExcept EvalError m
     , MonadExcept ProgramError m
     ) => m ()
handleMessage = ...data Nat = Zero | Suc Nat
class MonadReaderN (n :: Nat) r m where
  askN :: Proxy n -> m r
instance MonadReaderN Zero e (ReaderT e m) where
  askN _ = ask
instance (MonadTrans t,
          MonadReaderN n r m)
       => MonadReaderN (Suc n) r (t m)
  where
    askN _ = lift $ askN (Proxy :: Proxy n)type family
  Find
    (t :: (* -> *) -> (* -> *))
    (m :: * -> *)
    :: Nat where
  Find t (t m) = Zero
  Find t (p m) = Suc (Find t m)
type MonadReader r m =
  MonadReaderN (Find (ReaderT r) m) r m
ask :: forall r m. MonadReader r m => m r
ask = askN (Proxy :: Proxy (Find (ReaderT r) m))type family
  CanDo
    (t :: (* -> *))
    (eff :: k)
    :: Bool
data EffState s
data EffReader e
data EffWriter w
type family Find eff (m :: * -> *) :: Natfoo :: (MonadState User m, ...) => m ()
bar :: (MonadReader User m, ...) => m ()
baz = do
  foo
  bartype instance CanDo (StateT s m) eff = StateCanDo s eff
type family StateCanDo s eff where
  StateCanDo s (EffState s) = True
  StateCanDo s (EffReader s) = True
  StateCanDo s eff = False
instance MonadReaderN Zero r (StateT r m) where
    askN _ = getnewtype ZoomT big small m a = ZoomT (...)
  deriving (Functor, Applicative, Monad, ...)
instance
  MonadReader big m =>
  MonadReaderN Zero small (ZoomT big small m)
runZoom
  :: Lens big small
  -> ZoomT big small m a
  -> m a
runZoom l a = ...x = runState get 0No instance for (MonadStateN
                   (FindTrue
                      '[monad-classes-0.1:Control.Monad.Classes.State.StateCanDo
                          s0 (EffState a0),
                        CanDo Data.Functor.Identity.Identity (EffState a0)])
                   a0
                   (Control.Monad.Trans.State.Lazy.StateT
                      s0 Data.Functor.Identity.Identity))
  arising from a use of ‘it’
The type variables ‘s0’, ‘a0’ are ambiguous
Note: there are several potential instances:
  instance (Monad (t m), Control.Monad.Trans.Class.MonadTrans t,
            MonadStateN n s m, Monad m) =>
           MonadStateN ('Suc n) s (t m)
    -- Defined in ‘monad-classes-0.1:Control.Monad.Classes.State’
  instance Monad m =>
           MonadStateN 'Zero s (Control.Monad.Trans.State.Lazy.StateT s m)
    -- Defined in ‘monad-classes-0.1:Control.Monad.Classes.State’
In the first argument of ‘print’, namely ‘it’
In a stmt of an interactive GHCi command: print it