content: 
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  Mezzo.Compose.Builder
  -- Description :  Music builder
  -- Copyright   :  (c) Dima Szamozvancev
  -- License     :  MIT
  --
  -- Maintainer  :  ds709@cam.ac.uk
  -- Stability   :  experimental
  -- Portability :  portable
  --
  -- Pattern of combinatorially building musical terms of various types.
  --
  -----------------------------------------------------------------------------
  
  module Mezzo.Compose.Builder
      (
      -- * General builder types
        Spec
      , Conv
      , Mut
      , Term
      , AConv
      , AMut
      , ATerm
      , Mut'
      , spec
      , constConv
      -- * Music-specific builder types
      , RootS
      , RestS
      , ChorS
      , RootM
      , ChorM
      , ChorC
      , ChorC'
      , RootT
      , RestT
      , ChorT
      )
      where
  
  import Mezzo.Model
  
  import GHC.TypeLits
  
  -------------------------------------------------------------------------------
  -- General types
  -------------------------------------------------------------------------------
  
  -- | Specifier: specifies a value of some type which starts the building.
  type Spec t = forall m. (t -> m) -> m
  
  -- | Converter: converts a value of type s to a value of type t.
  type Conv s t = s -> Spec t
  
  -- | Mutator: mutates a value of type t.
  type Mut t = Conv t t
  
  -- | Terminator: finishes building a value of type t and returns a result of type r.
  type Term t r = t -> r
  
  -- | Converter with argument: converts a value of type s to a value of type t, consuming an argument of type a.
  type AConv a s t = s -> a -> Spec t
  
  -- | Mutator with argument: mutates a value of type t, consuming an argument of type a.
  type AMut a t = AConv a t t
  
  -- | Terminator with argument: finishes building a value of type t, returning a result of
  -- type r, consuming an argument of type a.
  type ATerm a t r = t -> a -> r
  
  -- | Flexible mutator: mutator that allows slight changes in the type (otherwise use 'Conv').
  type Mut' t t' = Conv t t'
  
  -- | Returns a new specifier for the given value.
  spec :: t -> Spec t
  spec i c = c i
  
  -- | A converter that ignores its argument and returns the given constant value.
  constConv :: t -> Conv s t
  constConv = const . spec
  
  -- | A mutator that does nothing.
  nop :: Mut t
  nop = spec
  
  -------------------------------------------------------------------------------
  -- Music specific types
  -------------------------------------------------------------------------------
  
  -- | Root specifier.
  type RootS r = Primitive r => Spec (Root r)
  
  -- | Rest specifier.
  type RestS = Spec (Pit Silence)
  
  -- | Chord specifier.
  type ChorS c = Primitive c => Spec (Cho c)
  
  -- | Root mutator.
  type RootM r r' = (Primitive r, Primitive r') => Mut' (Root r) (Root r')
  
  -- | Chord mutator.
  type ChorM c c' = (Primitive c, Primitive c') => Mut' (Cho c) (Cho c')
  
  -- | Converter from roots to chords.
  type ChorC' c r t i = (Primitive r, Primitive t, Primitive i) => AConv (Inv i) (Root r) (Cho (c r t i))
  
  -- | Converter from roots to chords, using the default inversion.
  type ChorC c r t = (Primitive r, Primitive t) => Conv (Root r) (Cho (c r t Inv0))
  
  -- | Note terminator.
  type RootT s r d = Primitive r => Term (Root r) (Music s (FromRoot r d))
  
  --  | Rest terminator.
  type RestT s d = Term (Pit Silence) (Music s (FromSilence d))
  
  -- | Chord terminator.
  type ChorT s c d = Primitive c => Term (Cho c) (Music s (FromChord c d))
  
  -- inKey :: KeyS key -> a -> a
  -- inKey key cont = let ?k = key in cont
  --
  --
  -- i :: (?k :: KeyS key) => RootS (DegreeRoot key I)
  -- i = spec Root
  --
  -- c :: RootS (PitchRoot (Pitch C Natural Oct3))
  -- c = spec Root
  --
  -- sharp :: RootM r (Sharpen r)
  -- sharp = constConv Root
  --
  -- maj :: ChorC Triad r MajTriad
  -- maj = constConv Cho
  --
  -- qn :: RootT r 8
  -- qn p = Note p Dur
  --
  -- qc :: KnownNat n => ChorT (c :: ChordType n) 8
  -- qc c = Chord c Dur
  
  
  -------------------------------------------------------------------------------
  -- Silly examples
  -- Most of these are quite pointless, but show that the pattern enables us to
  -- write DSLs with a very fluent feel.
  -------------------------------------------------------------------------------
  
  inc :: Mut Int
  inc i = spec (succ i)
  
  toString :: Conv Int String
  toString n = spec (show n)
  
  ex :: Mut String
  ex s = spec (s ++ "!")
  
  smile :: Term String String
  smile s = s ++ " :)"
  
  say :: String -> Spec String
  say = spec
  
  add :: Int -> Spec Int
  add = spec
  
  and' :: Mut t
  and' = nop
  
  to :: Int -> Mut Int
  to y x = spec (x + y)
  
  display :: Conv Int String
  display = spec . show
  
  result :: Term String String
  result = ("result: " ++)
  
  compute :: Double -> Spec Double
  compute = spec
  
  plus :: AMut Double Double
  plus i p = spec (i + p)
  
  please :: Term Double Double
  please = id
  
  percent :: Mut Double
  percent = nop
  
  of' :: Double -> Mut Double
  of' d p = spec (d * (p / 100))
  
  stack :: Spec [Int]
  stack = spec []
  
  push :: AMut Int [Int]
  push s v = spec (v : s)
  
  pop :: Mut [Int]
  pop = spec . tail
  
  end :: Term [Int] [Int]
  end = id
  