data-or-1.0.0: src/Data/Or.hs
{-# OPTIONS_GHC -Wall -fwarn-tabs #-}
{-# LANGUAGE CPP #-}
----------------------------------------------------------------
-- 2011.06.03
-- |
-- Module : Data.Or
-- Copyright : Copyright (c) 2010--2012 wren ng thornton
-- License : BSD
-- Maintainer : wren@community.haskell.org
-- Stability : provisional
-- Portability : Haskell98 + CPP
--
-- A data type for non-exclusive disjunction. This is helpful for
-- things like a generic merge function on sets\/maps which could
-- be union, mutual difference, etc. based on which 'Or' value a
-- function argument returns. Also useful for non-truncating zips
-- (cf. 'zipOr') and other cases where you sometimes want an 'Either'
-- and sometimes want a pair.
----------------------------------------------------------------
module Data.Or
( Or(Fst,Both,Snd), elimOr, eitherOr
-- * Non-truncating zipping functions
, zipOr, zipOrWith, zipOrBy, zipOrWithBy
) where
#ifdef __GLASGOW_HASKELL__
import GHC.Base (build)
#endif
----------------------------------------------------------------
-- | A data type for non-exclusive disjunction.
data Or a b = Fst a | Both a b | Snd b
deriving (Read, Show, Eq)
-- | Functional eliminator for 'Or'.
elimOr :: (a -> c) -> (a -> b -> c) -> (b -> c) -> Or a b -> c
elimOr f _ _ (Fst a) = f a
elimOr _ g _ (Both a b) = g a b
elimOr _ _ h (Snd b) = h b
{-# INLINE elimOr #-}
-- | Convert an 'Either' into an 'Or'.
eitherOr :: Either a b -> Or a b
eitherOr (Left a) = Fst a
eitherOr (Right b) = Snd b
{-# INLINE eitherOr #-}
----------------------------------------------------------------
-- | A variant of 'zip' which exhausts both lists, annotating which
-- list the elements came from. It will return zero or more @Both@,
-- followed by either zero or more @Fst@ or else zero or more @Snd@.
--
-- On GHC this is a \"good producer\" for list fusion.
zipOr :: [a] -> [b] -> [Or a b]
#ifdef __GLASGOW_HASKELL__
zipOr xs ys = build (\f z -> zipOrWithBy id f z xs ys)
#else
zipOr = zipOrWithBy id (:) []
#endif
{-# INLINE zipOr #-}
-- | A variant of 'zipOr' with a custom 'Or'-homomorphism.
--
-- On GHC this is a \"good producer\" for list fusion.
zipOrWith :: (Or a b -> c) -> [a] -> [b] -> [c]
#ifdef __GLASGOW_HASKELL__
zipOrWith k xs ys = build (\f z -> zipOrWithBy k f z xs ys)
#else
zipOrWith k = zipOrWithBy k (:) []
#endif
{-# INLINE zipOrWith #-}
-- | A variant of 'zipOr' with a custom list-homomorphism.
zipOrBy :: (Or a b -> c -> c) -> c -> [a] -> [b] -> c
zipOrBy = zipOrWithBy id
{-# INLINE zipOrBy #-}
-- | A variant of 'zipOr' with both a custom 'Or'-homomorphism and
-- a custom list-homomorphism. This is no more powerful than
-- 'zipOrBy', but it may be more convenient to separate the handling
-- of 'Or' from the handling of @(:)@.
zipOrWithBy
:: (Or a b -> c) -- ^ 'Or' homomorphism
-> (c -> d -> d) -- ^ list homomorphism, @(:)@ part
-> d -- ^ list homomorphism, @[]@ part
-> [a] -> [b] -> d
zipOrWithBy k f z = go
where
go [] [] = z
go [] (y:ys) = f (k (Snd y)) (go [] ys)
go (x:xs) [] = f (k (Fst x )) (go xs [])
go (x:xs) (y:ys) = f (k (Both x y)) (go xs ys)
----------------------------------------------------------------
----------------------------------------------------------- fin.