{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeFamilies           #-}
-- | Interface to access portions of a larger data structure.
--
-- Default operations to access elements from structs and arrays (e.g., a field
-- of a struct, an element of an array) allow obtaining the values of those
-- elements, but not modifying.
--
-- This module defines a common interface to manipulate portions of a larger
-- data structure. We define the interface in a generic way, using a type
-- class with two operations: one to set the value of the sub-element, and
-- one to update the value of such element applying a stream function.
module Copilot.Language.Operators.Projection
    ( Projectable (..) )
  where

import Copilot.Language.Stream (Stream)

infixl 8 =:
infixl 8 =$

-- | Common interface to manipulate portions of a larger data structure.
--
-- A projectable d s t means that it is possible to manipulate a sub-element s
-- of type t carried in a stream of type d.
class Projectable d s t | d s -> t where

  -- | Unapplied projection or element access on a type.
  data Projection d s t

  -- | Modify the value of a sub-element of a type in a stream of elements
  -- of that type.
  (=:) :: Projection d s t -> Stream t -> Stream d

  -- | Update the value of a sub-element of a type in a stream of elements of
  -- that type, by applying a function on streams.
  (=$) :: Projection d s t -> (Stream t -> Stream t) -> Stream d