packages feed

data-carousel-0.1.0.0: src/Data/Carousel.hs

{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE UnicodeSyntax #-}

-- |
-- Module: Data.Carousel
-- Copyright: Copyright © 2014 AlephCloud Systems, Inc.
-- License: MIT
-- Maintainer: Jon Sterling <jsterling@alephcloud.com>
-- Stability: experimental
--
module Data.Carousel
( Carousel
, empty
, cursor
, moveLeft
, moveRight
, dropCursor
, nub
, append
, clSequence
, clList
) where

import Control.Lens
import qualified Data.Foldable as F
import qualified Data.List as L
import qualified Data.Sequence as S

newtype Carousel α
  = Carousel
  { _clSequence ∷ S.Seq α
  } deriving (Show, Eq)

instance Functor Carousel where
  fmap f (Carousel sq) = Carousel $ fmap f sq

instance F.Foldable Carousel where
  foldMap f (Carousel sq) = F.foldMap f sq

instance Traversable Carousel where
  traverse f (Carousel sq) = fmap Carousel (traverse f sq)

clSequence ∷ Iso (Carousel α) (Carousel β) (S.Seq α) (S.Seq β)
clSequence = iso _clSequence Carousel

clList ∷ Iso (Carousel α) (Carousel β) [α] [β]
clList = clSequence . iso F.toList S.fromList


-- | There is guaranteed to be a cursor so long as the carousel is non-empty.
cursor ∷ Traversal' (Carousel α) α
cursor = clSequence . _head

-- | You can delete the cursor from the carousel; the items to its right will
-- move one over to the left.
dropCursor
  ∷ Carousel α
  → Carousel α
dropCursor = clSequence %~ (^. _tail)

-- | The carousel may be rotated to the right; this operation is written so as
-- to always guarantee the presence of a cursor in a non-empty carousel.
moveRight
  ∷ Carousel α
  → Carousel α
moveRight = clSequence %~ rotate . S.viewl
  where
    rotate
      ∷ S.ViewL α
      → S.Seq α
    rotate S.EmptyL = S.empty
    rotate (x S.:< xs) = xs S.|> x

-- | The carousel may be rotated to the left; this operation is written so as
-- to always guarantee the presence of a cursor in a non-empty carousel.
moveLeft
  ∷ Carousel α
  → Carousel α
moveLeft = clSequence %~ rotate . S.viewr
  where
    rotate
      ∷ S.ViewR α
      → S.Seq α
    rotate S.EmptyR = S.empty
    rotate (xs S.:> x) = x S.<| xs

-- | The empty carousel.
empty
  ∷ Carousel α
empty = Carousel S.empty

-- | Append a list of elements to the right side of the carousel.
append
  ∷ [α]
  → Carousel α
  → Carousel α
append xs = clSequence %~ (S.>< S.fromList xs)

-- | Remove all duplicate elements from the carousel. (TODO: this is inefficient)
nub
  ∷ Eq α
  ⇒ Carousel α
  → Carousel α
nub = clList %~ L.nub