packages feed

finite-1.4.1.1: src/lib/Finite/Collection.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Finite.Collection
-- Maintainer  :  Felix Klein
--
-- Allows to extend a finite instance from a single bound to a
-- collection of bounds, given as a finite ranged array.
--
-----------------------------------------------------------------------------

{-# LANGUAGE

    MultiParamTypeClasses
  , LambdaCase
  , ImplicitParams

  #-}

-----------------------------------------------------------------------------

module Finite.Collection where

-----------------------------------------------------------------------------

import Finite.Type
  ( T
  , v2t
  , (#<<)
  , FiniteBounds
  )

import Finite.Class
  ( Finite
  , elements
  , offset
  , value
  , index
  )

import Data.Array.IArray
  ( Array
  , Ix
  , (!)
  , inRange
  , assocs
  , range
  , bounds
  )

import Control.Exception
  ( assert
  )

-----------------------------------------------------------------------------

-- | The 'Collection' type provides a set of items, each assigning an
-- index of type @i@ to a value of type @a@.

data Collection i a =
  Item i a
  deriving
    ( -- | Equality can be checked for collections, if the index type
      -- and the elements can be checked for equality.
      Eq
    , -- | Order can be checked for collections, if the index type and
      -- the elements can be oredered.
      Ord
    , -- | Show a collection through its default constructor.
      Show
    )

-----------------------------------------------------------------------------

-- | Collections are used to extend Finite-Type / Context-Bounds pairs
-- to an array of bounds. At the same time the finite type is extended
-- to a collection of items that range over the same set of indices as
-- the bounds. Since the 'FiniteBounds' parameter always gives a
-- finite sized array of bounding parameters, it is guaranteed that
-- the connected collection has a finite bound as well.

instance (Ix i, Finite b a) => Finite (Array i b) (Collection i a) where

  elements t =
    sum $ map (elms t) $ assocs ?bounds

    where
      conv
        :: T (Collection i a) -> T a

      conv = undefined


      elms
        :: Finite b a => T (Collection i a) -> (i, b) -> Int

      elms t (_,b) =
        let ?bounds = b
        in elements $ conv t

  index (Item j v) =
    let
      -- array bounds
      (l,u) = bounds ?bounds
      -- list of indicies that appear before j
      ys = assert (inRange (l,u) j) $ init $ range (l,j)
      -- offset induces by these indices
      o = sum $ map ((elms v .) (?bounds !)) ys
      -- index of v with the bounds at position j
      idx = let ?bounds = ?bounds ! j
            in index v - offset #<< v
    in
      o + idx

    where
      elms
        :: Finite b a => a -> b -> Int

      elms v b =
        let ?bounds = b
        in elements $ v2t v

  value n =
    let
      -- elements of the whole collection
      e = elements $ v2t r
      -- array bounds
      b = bounds ?bounds
      -- target array index and reminder used as sub-index
      (j,m) = position (conv r) n (range b)
      -- result
      r = let ?bounds = ?bounds ! j
          in Item j $ value (m + offset (conv r))
    in
      assert (n >= 0 && n < e) r

    where
      conv
        :: Collection i a -> T a

      conv = undefined


      position
        :: (Ix i, Finite b a, FiniteBounds (Array i b))
        => T a -> Int -> [i] -> (i,Int)

      position t n = \case
        []   -> assert False undefined
        x:xr ->
          let m = let ?bounds = ?bounds ! x in elements t
          in if m <= n then position t (n - m) xr else (x,n)

-----------------------------------------------------------------------------