break (empty) → 1.0.0
raw patch · 4 files changed
+164/−0 lines, 4 filesdep +basedep +mtldep +transformerssetup-changed
Dependencies added: base, mtl, transformers
Files
- LICENSE +24/−0
- Setup.hs +2/−0
- break.cabal +29/−0
- src/Control/Break.hs +109/−0
+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (c) 2015 Gabriel Gonzalez+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.+ * Neither the name of Gabriel Gonzalez nor the names of other contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++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 OWNER 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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ break.cabal view
@@ -0,0 +1,29 @@+Name: break+Version: 1.0.0+Cabal-Version: >=1.10+Build-Type: Simple+License: BSD3+License-File: LICENSE+Copyright: 2015 Gabriel Gonzalez+Author: Gabriel Gonzalez+Maintainer: Gabriel439@gmail.com+Bug-Reports: https://github.com/Gabriel439/Haskell-Break-Library/issues+Synopsis: Break from a loop+Description: This library provides a simple and general API for exiting from+ loops+ .+ Read the tutorial in "Control.Break" to learn more+Category: Control+Source-Repository head+ Type: git+ Location: https://github.com/Gabriel439/Haskell-Optional-Library++Library+ HS-Source-Dirs: src+ Build-Depends:+ base >= 4.5 && < 5 ,+ mtl >= 2.1 && < 2.3,+ transformers >= 0.4.0.0 && < 0.5+ Exposed-Modules: Control.Break+ GHC-Options: -O2 -Wall+ Default-Language: Haskell2010
+ src/Control/Break.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++{-| Example usage:++> import Control.Break+> import Control.Monad.State+> import Prelude hiding (break)+>+> example :: State Int ()+> example = loop (do+> n <- lift get -- Inside a `loop`, wrap commands in `lift`+> if n < 10+> then lift (put (n + 1)) -- You keep looping by default+> else break () ) -- Use `break` to exit from the `loop`++The `loop` command runs the given command repeatedly until the command breaks+from the `loop` using `break`:++>>> execState example 0+10++For some effects (like `Control.Monad.Trans.State`), you can omit `lift`:++> example :: State Int ()+> example = loop (do+> n <- get+> if n < 10+> then put (n + 1)+> else break () )++ The `loop` will return whatever value you supply to `break`:++> example :: State Int Bool+> example = loop (do+> n <- get+> if n < 10+> then put (n + 1)+> else break True )++>>> runState example 0+(True,10)++-}++module Control.Break (+ -- * Break+ Break+ , loop+ , break++ -- * Re-exports+ , lift+ ) where++import Control.Applicative (Applicative)+import Control.Monad (forever)+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.Trans.Class (MonadTrans(..))+import Control.Monad.Trans.Except (ExceptT, runExceptT, throwE)+import Control.Monad.Cont (MonadCont )+import Control.Monad.State (MonadState )+import Control.Monad.Writer (MonadWriter)+import Prelude hiding (break)++{-| For the most common use cases you will:++ * build `Break` commands using `lift` or `break`++ * combine `Break` commands using @do@ notation++ * consume `Break` commands using `loop`++ The meaning of the type parameters:++ * @r@: the argument type of `break` and the return type of the `loop`++ * @m@: the base `Monad` that you are running in a `loop`++ * @a@: the return type of a `Break` command (not the same as the return+ value of the `loop`)+-}+newtype Break r m a = Break { unBreak :: ExceptT r m a }+ deriving+ ( Functor+ , Applicative+ , Monad+ , MonadTrans+ , MonadIO+ , MonadCont+ , MonadState s+ , MonadWriter w+ )++{-| `break` from a `loop`++ The argument you supply to `break` is the return value of the `loop`+-}+break :: Monad m => r -> Break r m a+break r = Break (throwE r)++{-| @(loop m)@ runs the action @\'m\'@ repeatedly until you `break` from the+ `loop`+-}+loop :: Monad m => Break r m () -> m r+loop m = do+ x <- runExceptT (unBreak (forever m))+ case x of+ Left r -> return r+ Right r -> return r