>>> import GHC.Internal.Data.IORef >>> r <- newIORef 0 >>> readIORef r 0 >>> writeIORef r 1 >>> readIORef r 1 >>> atomicWriteIORef r 2 >>> readIORef r 2 >>> modifyIORef' r (+ 1) >>> readIORef r 3 >>> atomicModifyIORef' r (\a -> (a + 1, ())) >>> readIORef r 4See also STRef and MVar.
>>> import Control.Monad.Except
>>> canFail = throwError "it failed" :: Except String Int >>> final = return 42 :: Except String IntCan be combined by allowing the first function to fail:
>>> runExcept $ canFail *> final Left "it failed"
>>> runExcept $ optional canFail *> final Right 42
data MyException = ThisException | ThatException deriving Show instance Exception MyExceptionThe default method definitions in the Exception class do what we need in this case. You can now throw and catch ThisException and ThatException as exceptions:
*Main> throw ThisException `catch` \e -> putStrLn ("Caught " ++ show (e :: MyException)) Caught ThisExceptionIn more complicated examples, you may wish to define a whole hierarchy of exceptions:
--------------------------------------------------------------------- -- Make the root exception type for all the exceptions in a compiler data SomeCompilerException = forall e . Exception e => SomeCompilerException e instance Show SomeCompilerException where show (SomeCompilerException e) = show e instance Exception SomeCompilerException compilerExceptionToException :: Exception e => e -> SomeException compilerExceptionToException = toException . SomeCompilerException compilerExceptionFromException :: Exception e => SomeException -> Maybe e compilerExceptionFromException x = do SomeCompilerException a <- fromException x cast a --------------------------------------------------------------------- -- Make a subhierarchy for exceptions in the frontend of the compiler data SomeFrontendException = forall e . Exception e => SomeFrontendException e instance Show SomeFrontendException where show (SomeFrontendException e) = show e instance Exception SomeFrontendException where toException = compilerExceptionToException fromException = compilerExceptionFromException frontendExceptionToException :: Exception e => e -> SomeException frontendExceptionToException = toException . SomeFrontendException frontendExceptionFromException :: Exception e => SomeException -> Maybe e frontendExceptionFromException x = do SomeFrontendException a <- fromException x cast a --------------------------------------------------------------------- -- Make an exception type for a particular frontend compiler exception data MismatchedParentheses = MismatchedParentheses deriving Show instance Exception MismatchedParentheses where toException = frontendExceptionToException fromException = frontendExceptionFromExceptionWe can now catch a MismatchedParentheses exception as MismatchedParentheses, SomeFrontendException or SomeCompilerException, but not other types, e.g. IOException:
*Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: MismatchedParentheses)) Caught MismatchedParentheses *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: SomeFrontendException)) Caught MismatchedParentheses *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: SomeCompilerException)) Caught MismatchedParentheses *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: IOException)) *** Exception: MismatchedParentheses
>>> bior (True, False) True
>>> bior (False, False) False
>>> bior (Left True) TrueEmpty structures yield False:
>>> bior (BiList [] []) FalseA True value finitely far from the left end yields True (short circuit):
>>> bior (BiList [False, False, True, False] (repeat False)) TrueA True value infinitely far from the left end hangs:
> bior (BiList (repeat False) [True]) * Hangs forever *An infinitely False value hangs:
> bior (BiList (repeat False) []) * Hangs forever *
>>> ref <- newIORef 42 >>> atomicModifyIORef ref (\a -> (a, a + 3)) 45 >>> readIORef ref 42
>>> ref <- newIORef 42 >>> atomicModifyIORef' ref (\a -> (a, a + 3)) 45 >>> readIORef ref 42
>>> ref <- newIORef 42 >>> atomicModifyIORef'_ ref (`div` 2) >>> readIORef ref 21
>>> ref <- newIORef 42 >>> atomicModifyIORef_ ref (`div` 2) >>> readIORef ref 21
>>> ref <- newIORef 42 >>> atomicWriteIORef ref 45 >>> readIORef ref 45
>>> ref <- newIORef 42 >>> modifyIORef ref (\a -> a + 6) >>> readIORef ref 48
>>> ref <- newIORef 42 >>> modifyIORef' ref (\a -> a + 3) >>> readIORef ref 45