{-# OPTIONS_HADDOCK hide, not-home #-}
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}

{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}

module Test.Fixie.Internal
  ( Note(..)
  , Function(..)
  , Call(..)
  , FixieT
  , FixieM
  , toSet
  , note
  , getFixture
  , getFunction
  , captureCall
  , unimplemented
  , outputNotesFunctionsT
  , outputNotesFunctionsetT
  , outputFunctionsNotesT
  , outputFunctionsetNotesT
  , valueNotesFunctionsT
  , valueNotesFunctionsetT
  , valueFunctionsNotesT
  , valueFunctionsetNotesT
  , notesOutputFunctionsT
  , notesOutputFunctionsetT
  , notesValueFunctionsT
  , notesValueFunctionsetT
  , notesFunctionsOutputT
  , notesFunctionsetOutputT
  , notesFunctionsValueT
  , notesFunctionsetValueT
  , functionsOutputNotesT
  , functionsValueNotesT
  , functionsNotesOutputT
  , functionsNotesValueT
  , functionsetOutputNotesT
  , functionsetValueNotesT
  , functionsetNotesOutputT
  , functionsetNotesValueT
  , outputNotesT
  , outputFunctionsT
  , outputFunctionsetT
  , valueNotesT
  , valueFunctionsT
  , valueFunctionsetT
  , notesOutputT
  , notesValueT
  , notesFunctionsT
  , notesFunctionsetT
  , functionsOutputT
  , functionsValueT
  , functionsNotesT
  , functionsetOutputT
  , functionsetValueT
  , functionsetNotesT
  , outputT
  , valueT
  , notesT
  , functionsT
  , functionsetT
  , outputNotesFunctionsM
  , outputNotesFunctionsetM
  , outputFunctionsNotesM
  , outputFunctionsetNotesM
  , valueNotesFunctionsM
  , valueNotesFunctionsetM
  , valueFunctionsNotesM
  , valueFunctionsetNotesM
  , notesOutputFunctionsM
  , notesOutputFunctionsetM
  , notesValueFunctionsM
  , notesValueFunctionsetM
  , notesFunctionsOutputM
  , notesFunctionsetOutputM
  , notesFunctionsValueM
  , notesFunctionsetValueM
  , functionsOutputNotesM
  , functionsValueNotesM
  , functionsNotesOutputM
  , functionsNotesValueM
  , functionsetOutputNotesM
  , functionsetValueNotesM
  , functionsetNotesOutputM
  , functionsetNotesValueM
  , outputNotesM
  , outputFunctionsM
  , outputFunctionsetM
  , valueNotesM
  , valueFunctionsM
  , valueFunctionsetM
  , notesOutputM
  , notesValueM
  , notesFunctionsM
  , notesFunctionsetM
  , functionsOutputM
  , functionsValueM
  , functionsNotesM
  , functionsetOutputM
  , functionsetValueM
  , functionsetNotesM
  , outputM
  , valueM
  , notesM
  , functionsM
  , functionsetM
  ) where

import Control.Monad.Except
import Control.Monad.Reader
import Control.Monad.Writer
import Data.Functor.Identity
import Data.String (IsString)
import Data.Set (Set)
import qualified Data.Set as Set (fromList)
import Data.Either.Combinators (fromRight')
import Data.Text (Text, pack)
import Data.Void (Void)

newtype Note = Note Text
  deriving (Show, Eq, IsString)

newtype Function = Function Text
  deriving (Show, Eq, Ord, IsString)

newtype Call = Call { _function :: Function }
  deriving (Show, Eq, Ord)

newtype FixieT f e m a = FixieT (ExceptT e (ReaderT (f (FixieT f e m)) (WriterT [Note] (WriterT [Call] m))) a)
  deriving (Functor, Applicative, Monad)

instance Monad m => MonadError e (FixieT f e m) where
  throwError e = do
    captureCall $ Call $ Function (pack "throwError")
    FixieT $ throwError e
  catchError (FixieT a) b = do
    captureCall $ Call $ Function (pack "catchError")
    FixieT $ catchError a ((\(FixieT c) -> c) . b)

instance MonadTrans (FixieT f e) where
  lift = FixieT . lift . lift . lift . lift

type FixieM f e = FixieT f e Identity

--

unimplemented :: String -> a
unimplemented name = error ("unimplemented fixture method `" ++ name ++ "`")

toSet :: Ord a => [a] -> Set a
toSet = Set.fromList

--

getFixture :: Monad m => FixieT f e m (f (FixieT f e m))
getFixture = FixieT $ lift ask

getFunction :: Monad m => (f (FixieT f e m) -> a) -> FixieT f e m a
getFunction f = FixieT $ lift (asks f)

note :: Monad m => Note -> FixieT f e m ()
note = FixieT . lift . lift . tell . (:[])

captureCall :: Monad m => Call -> FixieT f e m ()
captureCall = FixieT . lift . lift . lift . tell . (:[])

--

noVoid :: Either Void a -> a
noVoid = fromRight'

pluck :: (a, b, c) -> (a, b)
pluck (a, b, _) = (a, b)

swap_0_2_1 :: (a, b, c) -> (a, c, b)
swap_0_2_1 (a, b, c) = (a, c, b)

swap_1_0_2 :: (a, b, c) -> (b, a, c)
swap_1_0_2 (a, b, c) = (b, a, c)

swap_1_2_0 :: (a, b, c) -> (b, c, a)
swap_1_2_0 (a, b, c) = (b, c, a)

swap_2_0_1 :: (a, b, c) -> (c, a, b)
swap_2_0_1 (a, b, c) = (c, a, b)

swap_2_1_0 :: (a, b, c) -> (c, b, a)
swap_2_1_0 (a, b, c) = (c, b, a)

map_0 :: (a -> d) -> (a, b, c) -> (d, b, c)
map_0 f (a, b, c) = (f a, b, c)

map_1 :: (b -> d) -> (a, b, c) -> (a, d, c)
map_1 f (a, b, c) = (a, f b, c)

map_2 :: (c -> d) -> (a, b, c) -> (a, b, d)
map_2 f (a, b, c) = (a, b, f c)

--

outputNotesCalls :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Either e a, [Note], [Call])
outputNotesCalls f (FixieT m) = fmap flattenTuple $ runWriterT $ runWriterT $ runReaderT (runExceptT m) f
  where
    flattenTuple :: ((a, b), c) -> (a, b, c)
    flattenTuple ((a, b), c) = (a, b, c)

--

valueNotesCalls :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (a, [Note], [Call])
valueNotesCalls f x = strip <$> outputNotesCalls f x
  where
    strip :: (Either Void a, b, c) -> (a, b, c) 
    strip (a, b, c) = (noVoid a, b, c)

--

outputNotesFunctions :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Either e a, [Note], [Function])
outputNotesFunctions f x = fn <$> outputNotesCalls f x
  where
    fn :: (Either e a, [Note], [Call]) -> (Either e a, [Note], [Function])
    fn (a, b, c) = (a, b, map _function c)

valueNotesFunctions :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (a, [Note], [Function])
valueNotesFunctions f x = fn <$> valueNotesCalls f x
  where
    fn :: (a, b, [Call]) -> (a, b, [Function]) 
    fn (a, b, c) = (a, b, map _function c)

----

outputNotesFunctionsT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Either e a, [Note], [Function])
outputNotesFunctionsT = outputNotesFunctions

outputNotesFunctionsetT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Either e a, [Note], Set Function)
outputNotesFunctionsetT f x = map_2 toSet <$>  outputNotesFunctions f x

outputFunctionsNotesT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Either e a, [Function], [Note])
outputFunctionsNotesT f x = swap_0_2_1 <$> outputNotesFunctions f x

outputFunctionsetNotesT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Either e a, Set Function, [Note])
outputFunctionsetNotesT f x = map_1 toSet . swap_0_2_1 <$> outputNotesFunctions f x

valueNotesFunctionsT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (a, [Note], [Function])
valueNotesFunctionsT = valueNotesFunctions

valueNotesFunctionsetT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (a, [Note], Set Function)
valueNotesFunctionsetT f x = map_2 toSet <$> valueNotesFunctions f x

valueFunctionsNotesT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (a, [Function], [Note])
valueFunctionsNotesT f x = swap_0_2_1 <$> valueNotesFunctions f x

valueFunctionsetNotesT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (a, Set Function, [Note])
valueFunctionsetNotesT f x = map_1 toSet . swap_0_2_1 <$> valueNotesFunctions f x

--

notesOutputFunctionsT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Note], Either e a, [Function])
notesOutputFunctionsT f x = swap_1_0_2 <$> outputNotesFunctions f x

notesOutputFunctionsetT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Note], Either e a, Set Function)
notesOutputFunctionsetT f x = map_2 toSet . swap_1_0_2 <$> outputNotesFunctions f x

notesValueFunctionsT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m ([Note], a, [Function])
notesValueFunctionsT f x = swap_1_0_2 <$> valueNotesFunctions f x

notesValueFunctionsetT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m ([Note], a, Set Function)
notesValueFunctionsetT f x = map_2 toSet . swap_1_0_2 <$> valueNotesFunctions f x

notesFunctionsOutputT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Note], [Function], Either e a)
notesFunctionsOutputT f x = swap_1_2_0 <$> outputNotesFunctions f x

notesFunctionsetOutputT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Note], Set Function,  Either e a)
notesFunctionsetOutputT f x = map_1 toSet . swap_1_2_0 <$> outputNotesFunctions f x

notesFunctionsValueT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m ([Note], [Function], a)
notesFunctionsValueT f x = swap_1_2_0 <$> valueNotesFunctions f x

notesFunctionsetValueT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m ([Note], Set Function, a)
notesFunctionsetValueT f x = map_1 toSet . swap_1_2_0 <$> valueNotesFunctions f x

functionsOutputNotesT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Function], Either e a, [Note])
functionsOutputNotesT f x = swap_2_0_1 <$> outputNotesFunctions f x

functionsValueNotesT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m ([Function], a, [Note])
functionsValueNotesT f x = swap_2_0_1 <$> valueNotesFunctions f x

functionsNotesOutputT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Function], [Note], Either e a)
functionsNotesOutputT f x = swap_2_1_0 <$> outputNotesFunctions f x

functionsNotesValueT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m ([Function], [Note], a)
functionsNotesValueT f x = swap_2_1_0 <$> valueNotesFunctions f x

functionsetOutputNotesT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Set Function, Either e a, [Note])
functionsetOutputNotesT f x = map_0 toSet . swap_2_0_1 <$> outputNotesFunctions f x

functionsetValueNotesT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (Set Function, a, [Note])
functionsetValueNotesT f x = map_0 toSet . swap_2_0_1 <$> valueNotesFunctions f x

functionsetNotesOutputT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Set Function, [Note], Either e a)
functionsetNotesOutputT f x = map_0 toSet . swap_2_1_0 <$> outputNotesFunctions f x

functionsetNotesValueT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (Set Function, [Note], a)
functionsetNotesValueT f x = map_0 toSet . swap_2_1_0 <$> valueNotesFunctions f x

--

outputNotesT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Either e a, [Note])
outputNotesT f x = pluck <$> outputNotesFunctions f x

outputFunctionsT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Either e a, [Function])
outputFunctionsT f x = pluck . swap_0_2_1 <$> outputNotesFunctions f x

outputFunctionsetT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Either e a, Set Function)
outputFunctionsetT f x = pluck . map_1 toSet . swap_0_2_1 <$> outputNotesFunctions f x

valueNotesT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (a, [Note])
valueNotesT f x = pluck <$> valueNotesFunctions f x

valueFunctionsT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (a, [Function])
valueFunctionsT f x = pluck . swap_0_2_1 <$> valueNotesFunctions f x

valueFunctionsetT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (a, Set Function)
valueFunctionsetT f x = pluck . map_1 toSet . swap_0_2_1 <$> valueNotesFunctions f x

notesOutputT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Note], Either e a)
notesOutputT f x = pluck . swap_1_0_2 <$> outputNotesFunctions f x

notesValueT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m ([Note], a)
notesValueT f x = pluck . swap_1_0_2 <$> valueNotesFunctions f x

notesFunctionsT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Note], [Function])
notesFunctionsT f x = pluck . swap_1_2_0 <$> outputNotesFunctions f x

notesFunctionsetT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Note], Set Function)
notesFunctionsetT f x = pluck . map_1 toSet . swap_1_2_0 <$> outputNotesFunctions f x

functionsOutputT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Function], Either e a)
functionsOutputT f x = pluck . swap_2_0_1 <$> outputNotesFunctions f x

functionsValueT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m ([Function], a)
functionsValueT f x = pluck . swap_2_0_1 <$> valueNotesFunctions f x

functionsNotesT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m ([Function], [Note])
functionsNotesT f x = pluck . swap_2_1_0 <$> outputNotesFunctions f x

functionsetOutputT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Set Function, Either e a)
functionsetOutputT f x = pluck . map_0 toSet . swap_2_0_1 <$> outputNotesFunctions f x

functionsetValueT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m (Set Function, a)
functionsetValueT f x = pluck . map_0 toSet . swap_2_0_1 <$> valueNotesFunctions f x

functionsetNotesT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Set Function, [Note])
functionsetNotesT f x = pluck . map_0 toSet . swap_2_1_0 <$> outputNotesFunctions f x

outputT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Either e a)
outputT f x = (\(a,_,_) -> a) <$> outputNotesFunctions f x

valueT :: Monad m => f (FixieT f Void m) -> FixieT f Void m a -> m a
valueT f x = (\(a,_,_) -> a) <$> valueNotesFunctions f x

notesT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m [Note]
notesT f x = (\(_,b,_) -> b) <$> outputNotesFunctions f x

functionsT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m [Function]
functionsT f x = (\(_,_,c) -> c) <$> outputNotesFunctions f x

functionsetT :: Monad m => f (FixieT f e m) -> FixieT f e m a -> m (Set Function)
functionsetT f x = (\(_,_,c) -> toSet c) <$> outputNotesFunctions f x

--------

fixieM :: (a -> b -> Identity c) -> a -> b -> c
fixieM y f x = runIdentity (y f x)

outputNotesFunctionsM :: f (FixieM f e) -> FixieM f e a -> (Either e a, [Note], [Function])
outputNotesFunctionsM = fixieM outputNotesFunctionsT 

outputNotesFunctionsetM :: f (FixieM f e) -> FixieM f e a -> (Either e a, [Note], Set Function)
outputNotesFunctionsetM = fixieM outputNotesFunctionsetT

outputFunctionsNotesM :: f (FixieM f e) -> FixieM f e a -> (Either e a, [Function], [Note])
outputFunctionsNotesM = fixieM outputFunctionsNotesT

outputFunctionsetNotesM :: f (FixieM f e) -> FixieM f e a -> (Either e a, Set Function, [Note])
outputFunctionsetNotesM = fixieM outputFunctionsetNotesT

valueNotesFunctionsM :: f (FixieM f Void) -> FixieM f Void a -> (a, [Note], [Function])
valueNotesFunctionsM = fixieM valueNotesFunctionsT

valueNotesFunctionsetM :: f (FixieM f Void) -> FixieM f Void a -> (a, [Note], Set Function)
valueNotesFunctionsetM = fixieM valueNotesFunctionsetT

valueFunctionsNotesM :: f (FixieM f Void) -> FixieM f Void a -> (a, [Function], [Note])
valueFunctionsNotesM = fixieM valueFunctionsNotesT

valueFunctionsetNotesM :: f (FixieM f Void) -> FixieM f Void a -> (a, Set Function, [Note])
valueFunctionsetNotesM = fixieM valueFunctionsetNotesT

notesOutputFunctionsM :: f (FixieM f e) -> FixieM f e a -> ([Note], Either e a, [Function])
notesOutputFunctionsM = fixieM notesOutputFunctionsT

notesOutputFunctionsetM :: f (FixieM f e) -> FixieM f e a -> ([Note], Either e a, Set Function)
notesOutputFunctionsetM = fixieM notesOutputFunctionsetT

notesValueFunctionsM :: f (FixieM f Void) -> FixieM f Void a -> ([Note], a, [Function])
notesValueFunctionsM = fixieM notesValueFunctionsT

notesValueFunctionsetM :: f (FixieM f Void) -> FixieM f Void a -> ([Note], a, Set Function)
notesValueFunctionsetM = fixieM notesValueFunctionsetT

notesFunctionsOutputM :: f (FixieM f e) -> FixieM f e a -> ([Note], [Function], Either e a)
notesFunctionsOutputM = fixieM notesFunctionsOutputT

notesFunctionsetOutputM :: f (FixieM f e) -> FixieM f e a -> ([Note], Set Function,  Either e a)
notesFunctionsetOutputM = fixieM notesFunctionsetOutputT

notesFunctionsValueM :: f (FixieM f Void) -> FixieM f Void a -> ([Note], [Function], a)
notesFunctionsValueM = fixieM notesFunctionsValueT

notesFunctionsetValueM :: f (FixieM f Void) -> FixieM f Void a -> ([Note], Set Function, a)
notesFunctionsetValueM = fixieM notesFunctionsetValueT

functionsOutputNotesM :: f (FixieM f e) -> FixieM f e a -> ([Function], Either e a, [Note])
functionsOutputNotesM = fixieM functionsOutputNotesT

functionsValueNotesM :: f (FixieM f Void) -> FixieM f Void a -> ([Function], a, [Note])
functionsValueNotesM = fixieM functionsValueNotesT

functionsNotesOutputM :: f (FixieM f e) -> FixieM f e a -> ([Function], [Note], Either e a)
functionsNotesOutputM = fixieM functionsNotesOutputT

functionsNotesValueM :: f (FixieM f Void) -> FixieM f Void a -> ([Function], [Note], a)
functionsNotesValueM = fixieM functionsNotesValueT

functionsetOutputNotesM :: f (FixieM f e) -> FixieM f e a -> (Set Function, Either e a, [Note])
functionsetOutputNotesM = fixieM functionsetOutputNotesT

functionsetValueNotesM :: f (FixieM f Void) -> FixieM f Void a -> (Set Function, a, [Note])
functionsetValueNotesM = fixieM functionsetValueNotesT

functionsetNotesOutputM :: f (FixieM f e) -> FixieM f e a -> (Set Function, [Note], Either e a)
functionsetNotesOutputM = fixieM functionsetNotesOutputT

functionsetNotesValueM :: f (FixieM f Void) -> FixieM f Void a -> (Set Function, [Note], a)
functionsetNotesValueM = fixieM functionsetNotesValueT

outputNotesM :: f (FixieM f e) -> FixieM f e a -> (Either e a, [Note])
outputNotesM = fixieM outputNotesT

outputFunctionsM :: f (FixieM f e) -> FixieM f e a -> (Either e a, [Function])
outputFunctionsM = fixieM outputFunctionsT

outputFunctionsetM :: f (FixieM f e) -> FixieM f e a -> (Either e a, Set Function)
outputFunctionsetM = fixieM outputFunctionsetT

valueNotesM :: f (FixieM f Void) -> FixieM f Void a -> (a, [Note])
valueNotesM = fixieM valueNotesT

valueFunctionsM :: f (FixieM f Void) -> FixieM f Void a -> (a, [Function])
valueFunctionsM = fixieM valueFunctionsT

valueFunctionsetM :: f (FixieM f Void) -> FixieM f Void a -> (a, Set Function)
valueFunctionsetM = fixieM valueFunctionsetT

notesOutputM :: f (FixieM f e) -> FixieM f e a -> ([Note], Either e a)
notesOutputM = fixieM notesOutputT

notesValueM :: f (FixieM f Void) -> FixieM f Void a -> ([Note], a)
notesValueM = fixieM notesValueT

notesFunctionsM :: f (FixieM f e) -> FixieM f e a -> ([Note], [Function])
notesFunctionsM = fixieM notesFunctionsT

notesFunctionsetM :: f (FixieM f e) -> FixieM f e a -> ([Note], Set Function)
notesFunctionsetM = fixieM notesFunctionsetT

functionsOutputM :: f (FixieM f e) -> FixieM f e a -> ([Function], Either e a)
functionsOutputM = fixieM functionsOutputT

functionsValueM :: f (FixieM f Void) -> FixieM f Void a -> ([Function], a)
functionsValueM = fixieM functionsValueT

functionsNotesM :: f (FixieM f e) -> FixieM f e a -> ([Function], [Note])
functionsNotesM = fixieM functionsNotesT

functionsetOutputM :: f (FixieM f e) -> FixieM f e a -> (Set Function, Either e a)
functionsetOutputM = fixieM functionsetOutputT

functionsetValueM :: f (FixieM f Void) -> FixieM f Void a -> (Set Function, a)
functionsetValueM = fixieM functionsetValueT

functionsetNotesM :: f (FixieM f e) -> FixieM f e a -> (Set Function, [Note])
functionsetNotesM = fixieM functionsetNotesT

outputM :: f (FixieM f e) -> FixieM f e a -> (Either e a)
outputM = fixieM outputT

valueM :: f (FixieM f Void) -> FixieM f Void a -> a
valueM = fixieM valueT

notesM :: f (FixieM f e) -> FixieM f e a -> [Note]
notesM = fixieM notesT

functionsM :: f (FixieM f e) -> FixieM f e a -> [Function]
functionsM = fixieM functionsT

functionsetM :: f (FixieM f e) -> FixieM f e a -> (Set Function)
functionsetM = fixieM functionsetT