{-# LANGUAGE LambdaCase, OverloadedLists, TypeFamilies #-}
module Data.OneOrMore.Definition where

import Prelude (($), (.), error, Functor(..), Show, Eq)
import GHC.Exts (IsList(..))
import Control.Applicative
import Data.Foldable (Foldable(..))
import Data.Traversable (Traversable(..))

data OneOrMore a = One a
                 | More a (OneOrMore a)
                 deriving (Show, Eq)

instance IsList (OneOrMore a) where
  type Item (OneOrMore a) = a

  toList (One a) = [a]
  toList (More a rest) = a : toList rest

  fromList [] = error "Empty list"
  fromList [a] = One a
  fromList (a:as) = More a $ fromList as

instance Functor OneOrMore where
  fmap f (One x) = One (f x)
  fmap f (More x xs) = More (f x) $ fmap f xs

instance Foldable OneOrMore where
  foldr a b = foldr a b . toList

instance Applicative OneOrMore where
  pure = One
  functions <*> args = fromList [f x | f <- toList functions, x <- toList args]

instance Traversable OneOrMore where
  {-# INLINE traverse #-}
  traverse f (One x) = One <$> f x
  traverse f (More x xs) = More <$> f x <*> traverse f xs