acme-inator (empty) → 0.1.0.0
raw patch · 4 files changed
+168/−0 lines, 4 filesdep +basesetup-changed
Dependencies added: base
Files
- Acme/Inator.hs +111/−0
- EvilPlan.hs +29/−0
- Setup.lhs +6/−0
- acme-inator.cabal +22/−0
+ Acme/Inator.hs view
@@ -0,0 +1,111 @@+-- |+-- Module: Acme.Inator+-- License: Public Domain+-- Maintainer: Mark Lentczner <mzero@glyphic.com>+-- Stability: unstable, may self-destruct+-- Portability: portable+--+-- Construction and operation of evil inventions in the Tri-State area.+-- Based on the pioneering work of Dr. Heinz Doofenschmirtz.++module Acme.Inator (+ -- * Evil Inventions+ EvilInvention,+ inator, selfDestruct,++ -- * Secret Agents+ Agent(..),+ perryThePlatypus,+ TrappedAgent,++ -- * The TriStateArea+ TriStateArea,+ activate,+ whileTrapping,+) where++import Control.Monad (liftM)++-- | An 'EvilInvention' is like a normal function @a -> b@, only used in evil+-- plans. It will only function in the context of a 'TrappedAgent'. See+-- 'activate' for how to turn one one.+type EvilInvention a b = (TrappedAgent, a) -> b++-- | Combinator to turn a function into an 'EvilInvention'. Typically applied+-- via the '.' operator, like so:+--+-- > incrementinator :: EvilInvention Int Int+-- > incrementinator = (+1) . inator+inator :: (TrappedAgent, a) -> a+inator = snd++-- | /Warning:/ All 'EvilInvention's have a 'selfDestruct' ability. When an+-- 'EvilInvention' self-destructs, all effects of evil plans in the+-- 'TriStateArea' are nullified, as if 'Nothing' ever happened.+selfDestruct :: EvilInvention a b -> TriStateArea ()+selfDestruct _ = fail "Kaboom!"++++-- | Agents are secret, and distinguished only by their letter designations.+data Agent = Agent Char+ deriving (Eq, Ord, Bounded, Read, Show)++-- | 'Agent' @\'P\'@+perryThePlatypus :: Agent+perryThePlatypus = Agent 'P'++-- | When trapped, an 'Agent' enables an 'EvilInvention' to be 'activate'd and+-- then used. The scope of trapping an 'Agent' is strictly delimited.+-- See 'whileTrapping'.+data TrappedAgent = TrappedAgent Agent+++-- | Activation and operation of an 'EvilInvention' is strictly limited to the+-- 'TriStateArea'. Plans executed in the 'TriStateArea' may 'fail', causing the+-- whole plan to have no externally visible effect.+data TriStateArea a = TriStateArea { takeOver :: TrappedAgent -> Maybe a }+instance Functor TriStateArea where+ fmap = liftM+instance Monad TriStateArea where+ return = TriStateArea . const . Just+ f >>= g = TriStateArea (\ta -> takeOver f ta >>= flip takeOver ta . g)+ fail _ = TriStateArea $ const Nothing++-- | The 'Agent' trapped in the 'TriStateArea'.+trappedAgent :: TriStateArea TrappedAgent+trappedAgent = TriStateArea Just++-- | 'EvilInvention's must be activated before use. The activated machine can+-- then be applied to suitable targets of scorn and dislike. /N.B.:/ Activation+-- and subsequent operation of an 'EvilInvention' can only be performed in the+-- 'TriStateArea'.+--+-- > evilPlan :: TriStateArea Int+-- > evilPlan = do+-- > zap <- activate incrementinator+-- > as <- mapM zap [1..37]+-- > b <- zap 38 -- I never really liked the number 38+-- > selfDestruct incrementinator+-- > cs <- mapM zap [39..100]+-- > return $ sum as + b + sum cs+activate :: EvilInvention a b -> TriStateArea (a -> TriStateArea b)+activate contraption = return $ \a -> do+ ta <- trappedAgent+ return $ contraption (ta,a)++-- | To execute any plan (evil or 'otherwise') in the 'TriStateArea', an+-- 'Agent' must be trapped with this function, and held for the duration of+-- of the plan.+--+-- > executeEvilPlan = whileTrapping perryThePlatypus evilPlan+-- >+-- > main :: IO ()+-- > main = do+-- > putStrLn $+-- > case executeEvilPlan of+-- > Nothing -> "Curse you, Perry the Platypus!"+-- > Just a -> "Ha ha! I have incremented the TriStateArea to " ++ show a++whileTrapping :: Agent -> TriStateArea a -> Maybe a+whileTrapping a f = takeOver f $ TrappedAgent a
+ EvilPlan.hs view
@@ -0,0 +1,29 @@+-- | Run an evil plan to increment the Tri-State area with the incrementinator.++module Main (+ main+) where++import Acme.Inator++incrementinator :: EvilInvention Int Int+incrementinator = (+1) . inator++evilPlan :: TriStateArea Int+evilPlan = do+ zap <- activate incrementinator+ as <- mapM zap [1..37]+ b <- zap 38 -- I never really liked the number 38+ selfDestruct incrementinator+ cs <- mapM zap [39..100]+ return $ sum as + b + sum cs++executeEvilPlan :: Maybe Int+executeEvilPlan = whileTrapping perryThePlatypus evilPlan++main :: IO ()+main = do+ putStrLn $+ case executeEvilPlan of+ Nothing -> "Curse you, Perry the Platypus!"+ Just a -> "Aha! I have incremented the tri-state area to " ++ show a
+ Setup.lhs view
@@ -0,0 +1,6 @@+#!/usr/bin/runhaskell +> module Main where+> import Distribution.Simple+> main :: IO ()+> main = defaultMain+
+ acme-inator.cabal view
@@ -0,0 +1,22 @@+Name: acme-inator+Version: 0.1.0.0+License: PublicDomain+Author: Mark Lentczner <mzero@glyphic.com>+Maintainer: Mark Lentczner <mzero@glyphic.com>+Category: Acme+Build-type: Simple+Cabal-version: >=1.8+Synopsis: Evil inventions in the Tri-State area+Description:+ Construction and operation of evil inventions in the Tri-State area.+ Based on the pioneering work of Dr. Heinz Doofenshmirtz.++Library+ Exposed-modules: Acme.Inator+ Build-depends: base == 4.*+ Ghc-options: -fwarn-tabs -Wall++Executable evilplan+ Main-is: EvilPlan.hs+ Build-depends: base == 4.*+ Ghc-options: -fwarn-tabs -Wall