module Voting.Protocol.Utils where

import Control.Applicative (Applicative(..))
import Data.Bool
import Data.Eq (Eq(..))
import Data.Foldable (sequenceA_)
import Data.Function (($))
import Data.Functor ((<$))
import Data.Maybe (Maybe(..), maybe)
import Data.Traversable (Traversable(..))
import qualified Data.List as List

-- | Like ('.') but with two arguments.
o2 :: (c -> d) -> (a -> b -> c) -> a -> b -> d
o2 f g = \x y -> f (g x y)
infixr 9 `o2`
{-# INLINE o2 #-}

-- | NOTE: check the lengths before applying @f@.
isoZipWith :: (a->b->c) -> [a]->[b]->Maybe [c]
isoZipWith f as bs
 | List.length as /= List.length bs = Nothing
 | otherwise = Just (List.zipWith f as bs)

-- | NOTE: check the lengths before applying @f@.
isoZipWith3 :: (a->b->c->d) -> [a]->[b]->[c]->Maybe [d]
isoZipWith3 f as bs cs
 | al /= List.length bs = Nothing
 | al /= List.length cs = Nothing
 | otherwise = Just (List.zipWith3 f as bs cs)
 where al = List.length as

isoZipWithM ::
 Applicative f =>
 f () -> (a->b->f c) -> [a]->[b]->f [c]
isoZipWithM err f as bs =
        maybe ([] <$ err) sequenceA $
                isoZipWith f as bs

isoZipWithM_ ::
 Applicative f =>
 f () -> (a->b->f c) -> [a]->[b]->f ()
isoZipWithM_ err f as bs =
        maybe err sequenceA_ $
                isoZipWith f as bs

isoZipWith3M ::
 Applicative f =>
 f () -> (a->b->c->f d) -> [a]->[b]->[c]->f [d]
isoZipWith3M err f as bs cs =
        maybe ([] <$ err) sequenceA $
                isoZipWith3 f as bs cs

isoZipWith3M_ ::
 Applicative f =>
 f () -> (a->b->c->f d) -> [a]->[b]->[c]->f ()
isoZipWith3M_ err f as bs cs =
        maybe err sequenceA_ $
                isoZipWith3 f as bs cs