IndexedList-0.1.0.0: Data/List/Indexed/Counted.hs
{- |
Module : Data.List.Indexed.Counted
Description : A library providing length-indexed and element-indexed lists which sit somewhere between homogeneous and fully heterogeneous lists.
Copyright : Copyright (c) 2014 Kenneth Foner
Maintainer : kenneth.foner@gmail.com
Stability : experimental
Portability : non-portable
This module implements homogeneous counted lists, which are type-indexed by length.
-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Data.List.Indexed.Counted where
import Data.Numeric.Witness.Peano
import Control.Applicative
import Data.List hiding ( replicate , zip )
import Prelude hiding ( replicate , zip )
infixr 5 :::
-- | Counted lists are indexed by length in the type.
data CountedList n a where
(:::) :: a -> CountedList n a -> CountedList (Succ n) a
CountedNil :: CountedList Zero a
instance (Show x) => Show (CountedList n x) where
showsPrec p xs = showParen (p > 10) $
(showString $ ( intercalate " ::: "
$ map show
$ unCount xs ) ++ " ::: CountedNil")
-- | The 'count' of a list is the natural number corresponding to its length.
count :: CountedList n a -> Natural n
count CountedNil = Zero
count (x ::: xs) = Succ (count xs)
-- | Convert a counted list to a regular Haskell list.
unCount :: CountedList n a -> [a]
unCount CountedNil = []
unCount (x ::: xs) = x : unCount xs
-- | Replicate some element a certain number of times.
replicate :: Natural n -> x -> CountedList n x
replicate Zero _ = CountedNil
replicate (Succ n) x = x ::: replicate n x
-- | Appending two counted lists yields one of length equal to the sum of the lengths of the two initial lists.
append :: CountedList n a -> CountedList m a -> CountedList (m + n) a
append CountedNil ys = ys
append (x ::: xs) ys = x ::: append xs ys
-- | Take the nth element of a list. We statically prevent taking the nth element of a list of length less than n.
nth :: (n < m) => Natural n -> CountedList m a -> a
nth Zero (a ::: _) = a
nth (Succ n) (_ ::: as) = nth n as
nth _ _ = error "nth: the impossible occurred" -- like in minus, GHC can't prove this is unreachable
-- | Pad the length of a list to a given length. If the number specified is less than the length of the list given,
-- it won't pass the type-checker.
padTo :: (m <= n) => Natural n -> x -> CountedList m x -> CountedList ((n - m) + m) x
padTo n x list =
list `append` replicate (n `minus` count list) x
-- | Zip two equal-length lists together.
zip :: CountedList n a -> CountedList n b -> CountedList n (a,b)
zip (a ::: as) (b ::: bs) = (a,b) ::: zip as bs
zip CountedNil _ = CountedNil
zip _ CountedNil = CountedNil
instance Functor (CountedList n) where
fmap f CountedNil = CountedNil
fmap f (a ::: as) = f a ::: fmap f as
instance (ReifyNatural n) => Applicative (CountedList n) where
pure x = replicate (reifyNatural :: Natural n) x
fs <*> xs = uncurry id <$> zip fs xs