MonadStack (empty) → 0.1.0.1
raw patch · 5 files changed
+134/−0 lines, 5 filesdep +basedep +mtlsetup-changed
Dependencies added: base, mtl
Files
- LICENSE +24/−0
- MonadStack.cabal +26/−0
- README.md +2/−0
- Setup.hs +2/−0
- src/Control/Monad/MonadStack.hs +80/−0
+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (c) 2015, bhurt+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++* Redistributions of source code must retain the above copyright notice, this+ list of conditions and the following disclaimer.++* Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ MonadStack.cabal view
@@ -0,0 +1,26 @@+-- Initial MonadStack.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/++name: MonadStack+version: 0.1.0.1+synopsis: Generalizing lift to monad stacks+-- description: +homepage: https://github.com/bhurt/MonadStack+license: BSD2+license-file: LICENSE+author: Brian Hurt+maintainer: bhurt42@gmail.com+-- copyright: +category: Control+build-type: Simple+extra-source-files: README.md+cabal-version: >=1.10++library+ exposed-modules: Control.Monad.MonadStack+ -- other-modules: + -- other-extensions: + build-depends: base >=4.8 && <4.9,+ mtl >= 2.2 && <2.3+ hs-source-dirs: src+ default-language: Haskell2010
+ README.md view
@@ -0,0 +1,2 @@+# MonadStack+Allow lifting from any level in a monad transformer stack up to any higher level.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Control/Monad/MonadStack.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}++{- |+Module: Control.Monad.MonadStack+Description: A multi-level lift through a monad transformer stack.+Copyright: (C) 2015 by Brian Hurt+License: BSD 2-Clause+Maintainer: Brian Hurt <bhurt42@gmail.com>+Stability: experimental+Portability: safe++MonadStack provides a multi-level @lift@ function, called @liftFrom@.+It allows lifting from an arbitrary monad in a monad transformer stack+up to any higher monad in that stack. And example use might be:++> newtype MyMonad = MyMonad ... deriving (Monad)+>+> doFoo :: MonadStack MyMonad m => something -> m whatever+> doFoo arg = liftFrom go+> where+> go :: MyMonad whatever+> go = do ...++This allows calling doFoo either in the MyMonad monad, or in any monad+transformer stack on top of the MyMonad.++MonadStack is similar to the @Control.Monad.Base@ module from the+<https://hackage.haskell.org/package/transformers-base transformers-base>+package, except that there is no functional dependency between the+monads. A monad transformer stack can only have one base, but it can+have several MonadStack implementations.++MonadStack is very similar to the @Control.Monad.Lifter@ module from the+<https://hackage.haskell.org/package/MonadCompose MonadCompose> package,+with two exceptions. One, MonadStack does not require the+OverlappingInstances and UndecidableInstances extensions- both of which+are prone to generating hard to diagnose bugs. But this implies two,+that MonadStack is much less feature-rich than Lifter is. Specifically,+MonadStack only works with "proper" monad transformers (those that+implment @MonadTrans@), while Lifter generalizes the notion of lifting+and works with more different types of monads, especially @MonadPlus@.++-}+module Control.Monad.MonadStack where++ import Control.Monad.Trans++ -- | A multi-level lifter class.+ --+ -- The existance of an implementation of @MonadStack m n@ implies+ -- that is is possible to convert an @m a@ into an @n a@ via+ -- zero or more applications of @lift@.+ class MonadStack m n where+ liftFrom :: m a -> n a++ -- | The base case implementation+ --+ -- You can always convert an @m a@ into an @m a@ by applying 0+ -- lifts. This is like treating an @m a@ as a zero-level monad+ -- transformer stack (a monad transformer stack with no monad+ -- transformers), and @liftFrom@ is just the @id@ function.+ instance MonadStack m m where+ liftFrom = id++ -- | The inductive step implementation+ --+ -- If there exists an implementation of @MonadStack k m@ for+ -- monads @k@ and @m@ (that is, we can perform a @liftFrom@ to+ -- convert a @k a@ to a @m a@), and n is a monad transformer,+ -- then we can construct an implementation of @MonadStack k (n m)@,+ -- by just adding one more @lift@ to the @liftFrom@.++ -- Conceptually, if I can get from a k a to an m a via some+ -- sequence of lifts, and n is a monad transformer, then I can+ -- get from a k a to a n m a with one more lift. Or, if I can+ -- lift through an @n@-level monad transformer stack, I can+ -- lift through a @n+1@ level monad transformer stack.+ instance (Monad k, Monad m, MonadTrans n, MonadStack k m)+ => MonadStack k (n m) where+ liftFrom = lift . liftFrom