{-# LANGUAGE 
  NoImplicitPrelude,
  FlexibleContexts,
  NoMonomorphismRestriction,
  FlexibleInstances,
  MultiParamTypeClasses
#-}

module DDF.IO (module DDF.IO, module DDF.List, module DDF.Char, module DDF.Unit) where

import DDF.List
import DDF.Char
import DDF.Unit
import qualified Prelude as M

string [] = nil
string (c:str) = cons2 (char c) (string str)

class (List r, Unit r, Char r) => IO r where
  putStrLn :: r h (String -> M.IO ())
  ioMap :: r h ((a -> b) -> M.IO a -> M.IO b)
  ioPure :: r h (a -> M.IO a)
  ioAP :: r h (M.IO (a -> b) -> M.IO a -> M.IO b)
  ioBind :: r h (M.IO a -> (a -> M.IO b) -> M.IO b)
  ioBind = lam2 $ \m f -> join1 (map2 f m)
  ioJoin :: r h (M.IO (M.IO a) -> M.IO a)
  ioJoin = lam $ \m -> bind2 m id
  {-# MINIMAL putStrLn, ioMap, ioPure, ioAP, (ioBind | ioJoin) #-}

instance IO r => Functor r M.IO where
  map = ioMap

instance IO r => Applicative r M.IO where
  pure = ioPure
  ap = ioAP

instance IO r => Monad r M.IO where
  join = ioJoin
  bind = ioBind

putStrLn1 = app putStrLn