+module Voting.Protocol.Utils where
+
+import Control.Applicative (class Applicative, (<$))
+import Data.Boolean (otherwise)
+import Data.Eq (class Eq, (==), (/=))
+import Data.Function (($))
+import Data.List (List, (:))
+import Data.List as List
+import Data.List.Lazy as LL
+import Data.Maybe (Maybe(..), maybe)
+import Data.Traversable (sequence)
+import Data.Unit (Unit)
+
+-- | The 'zipWith3' function takes a function which combines three
+-- elements, as well as three lists and returns a list of their point-wise
+-- combination, analogous to 'zipWith'.
+zipWith3 :: forall a b c d. (a->b->c->d) -> List a->List b->List c->List d
+zipWith3 z = go
+ where
+ go (a:as) (b:bs) (c:cs) = z a b c : go as bs cs
+ go _ _ _ = List.Nil
+
+-- | NOTE: check the lengths before applying @f@.
+isoZipWith :: forall a b c. (a->b->c) -> List a->List b->Maybe (List 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 :: forall a b c d. (a->b->c->d) -> List a->List b->List c->Maybe (List d)
+isoZipWith3 f as bs cs
+ | List.length as /= List.length bs = Nothing
+ | List.length as /= List.length cs = Nothing
+ | otherwise = Just (zipWith3 f as bs cs)
+
+isoZipWithM :: forall f a b c.
+ Applicative f =>
+ f Unit -> (a->b->f c) -> List a->List b->f (List c)
+isoZipWithM err f as bs =
+ maybe (List.Nil <$ err) sequence $
+ isoZipWith f as bs