packages feed

flexiwrap-0.1.0: Data/Flex/Utils.hs

{-# LANGUAGE ScopedTypeVariables, Rank2Types #-}
-- .$Header: c:/Source/Haskell/Wrapper/Data/Flex/RCS/Utils.hs,v 1.5 2011/09/20 23:38:55 dosuser Exp dosuser $
module Data.Flex.Utils (
    -- * Various utility functions for handling wrappers
    -- ** Wrapper/unwrapper composition
    inCompose, inCompose2,
    -- ** Constructing @'Monad'@ bind (@'>>='@) for wrapped values
    bindWrapper,
    -- ** Another popular composition combinator
    on
    -- ** Semantic editor combinators
    -- (<http://conal.net/blog/posts/semantic-editor-combinators/>)
    , result, argument
) where

-- | Place (by composition) two functions round another function
circumpose :: (c -> d) -> (a -> b) -> (b -> c) -> (a -> d)
circumpose left right = (left .) . (. right)

-- | Bracket (by composition) a function by two other functions.
-- (\'In' as in infix.)

-- Sometimes more convenient than @'circumpose'@
inCompose :: (a -> b) -> (c -> d) -> (b -> c) -> (a -> d)
inCompose = flip circumpose

-- | A generalisation of @'inCompose'@ to two-argument functions
inCompose2 :: (forall a. f a -> a) -> (d -> e) ->
    (b -> c -> d) -> (f b -> f c -> e)
inCompose2 unwrap wrap = inCompose unwrap $ inCompose unwrap wrap

-- | Change the result of a function
result :: (b -> c) -> (a -> b) -> (a -> c)
result = (.)

-- | Change the argument of a function
argument :: (a -> b) -> (b -> c) -> (a -> c)
argument = flip (.)

-- | Handy utility function
infixl 8 `on`
on :: (b -> b -> c) -> (a -> b) -> (a -> a -> c)
(op `on` f) x y = f x `op` f y

-- | Utility function to construct @'>>='@ for a target monad @t@ from
-- the @'>>='@ from an implementation monad @i@
bindWrapper ::
    (forall q. t q -> i q)
    -- ^ wrap:   function from target monad to implementation monad
    -> (d -> e)
    -- ^ unwrap: vice versa (@i q -> t q@)
    -> (i a -> (c -> i b) -> d)
    -- ^ @'>>='@ in the implementation monad
    -> t a -> (c -> t b) -> e
bindWrapper wrap unwrap = inCompose wrap $ inCompose (result wrap) unwrap

-- vim: expandtab:tabstop=4:shiftwidth=4