needle (empty) → 0.1.0.0
raw patch · 7 files changed
+812/−0 lines, 7 filesdep +basedep +containersdep +haskell-src-metasetup-changed
Dependencies added: base, containers, haskell-src-meta, mtl, parsec, parsec-extra, template-haskell, text, vector
Files
- Control/Arrow/Needle.hs +63/−0
- Control/Arrow/Needle/Internal/UnevenGrid.hs +276/−0
- Control/Arrow/Needle/Parse.hs +308/−0
- Control/Arrow/Needle/TH.hs +109/−0
- LICENSE +20/−0
- Setup.hs +2/−0
- needle.cabal +34/−0
+ Control/Arrow/Needle.hs view
@@ -0,0 +1,63 @@+{-|+Module : Control.Arrow.Needle+Description : ASCII-fied arrow notation.+Copyright : (c) 2014 Josh Kirklin+License : MIT+Maintainer : jjvk2@cam.ac.uk++Needle is a domain specific language for ASCII-fied arrow notation. This module enables the use of needle within Haskell by making use of Template Haskell.++In needle, data travels along rails. There are three types of rail, and data travels in different directions on each:++ [@=@] left to right+ [@\\@] down+ [@/@] up++Data enters a rail with @}@, and exits with @>@.++When rails are joined, their contents are concatenated. When rails are split, their contents are duplicated.++An external arrow can be embedded in a rail by enclosing it between a @{@ and a @}@.++Inputs and outputs of rails can be asigned labels with a @:@.++Rails can cross one another, if one of the rails has gone \'underground\' by entering a \'tunnel\'. A tunnel entrance is specified by a @)@, and a tunnel exit is specified by a @(@.++Most questions should be answered by a short example:++> import Control.Arrow.Needle+>+> nTest :: (Int, Int, Int) -> (Int, (Int, Int, Int))+> nTest = [nd|+> aLabel:==={div 2}===\+> }====\ \+> {uncurry (+)}==\=================) \ (==>+> }====/ \ \+> \ \=={nTriple}=>+> \ +> }=={uncurry (-)}====:aLabel+> |]+> +> nTriple = [nd|+> }==\==>+> \==>+> \==>+> |]++>>> nTest (3,2,1)+(5,(-1,-1,-1))++-}++module Control.Arrow.Needle (+ nd+ , ndFile+ -- * Reexported for your convenience+ , module Control.Arrow+) where+++import Control.Arrow++import Control.Arrow.Needle.TH (nd, ndFile)+
+ Control/Arrow/Needle/Internal/UnevenGrid.hs view
@@ -0,0 +1,276 @@+{-|+Module : Control.Arrow.Needle.Internal.UnevenGrid+Description : Data structure used in parsing needle diagrams+Copyright : (c) Josh Kirklin+License : MIT+Maintainer : jjvk2@cam.ac.uk++Implements a 'Grid' data structure which can be examined and moved around with a monad 'GridExamine', used in needle parsing.+-}++{-# LANGUAGE DeriveFunctor, OverloadedLists, GeneralizedNewtypeDeriving, TupleSections#-}++module Control.Arrow.Needle.Internal.UnevenGrid (+ -- * Grids+ Grid ()+ , grid+ , prettyGrid+ , height+ , GridPosition+ , (!!?)+ , findPositions+ -- * Examining+ , GridExamine ()+ , gridExamine+ , branch+ , getGrid+ , getPosition+ , putPosition+ , modifyPosition+ , width+ -- ** Moving and accessing+ , hereGet+ , leftGet+ , rightGet+ , lUpGet+ , lDownGet+ , rUpGet+ , rDownGet+ ) where++import Prelude as Pre++import Data.Foldable as F++import Data.Vector as V+import Data.Maybe +import Data.List +import Data.Sequence as S++import Control.Applicative+import Control.Monad.State as St+import Control.Monad.Reader++import Control.Arrow++-- | A 'Grid' is a list of rows, the elements of which are not necessarily +-- aligned, with the exception that the left edge of the grid is aligned.+--+-- So for example, the following is a valid shape for a 'Grid':+--+-- > ____________+-- > |___|___|_|__|+-- > |__|_|_|__|_|__+-- > |_|______|_____|+-- >+--++newtype Grid e = Grid { rows :: Vector (GridRow e) }+ deriving (Eq, Functor, Show)++newtype GridRow e = GridRow { elements :: Vector (GridElem e) } + deriving (Eq, Functor, Show)++fromLeft :: GridRow e -> Int -> Maybe Int+fromLeft (GridRow row) n = V.findIndex ((> n) . end) $ row++data GridElem e = GridElem {+ end :: Int+ , unwrap :: e+} deriving (Eq, Functor, Show)++type GridPosition = (Int, Int)++-- | Generate a 'Grid' from a list of rows of elements and widths.++grid :: [[(e, Int)]] -> Grid e+grid rs = Grid . V.fromList . Pre.map (GridRow . V.fromList) $ gridElems+ where+ widths = Pre.map (Pre.map snd) rs+ es = Pre.map (Pre.map fst) rs+ f a = Pre.zipWith (+) (0 : f a) a+ ends = Pre.map f widths+ gridElems = Pre.zipWith (Pre.zipWith GridElem) ends es++-- | Pretty print a grid++prettyGrid :: (e -> Int -> String) -> Grid e -> String+prettyGrid eShow grid = unlines . Pre.map Pre.concat $ lShowns+ where+ untyped = V.map elements . rows $ grid+ widths = V.map ((\a -> V.zipWith (-) a (0 `cons` a)) . V.map end) untyped+ unwrappeds = V.map (V.map unwrap) untyped+ showns = V.zipWith (V.zipWith eShow) unwrappeds widths+ lShowns = Pre.map V.toList . V.toList $ showns++-- | Get the grid height++height :: Grid e -> Int+height = V.length . rows++-- | Get the element at a certain position in the grid. The top left block is+-- in the (0,0) position.++(!!?) :: Grid e -> GridPosition -> Maybe e+(!!?) grid (rowPos, elemPos) = do+ row <- rows grid !? rowPos+ element <- elements row !? elemPos+ return $ unwrap element++-- | Return a list of positions satisfying a predicate in a grid, in reading order.++findPositions :: (e -> Bool) -> Grid e -> [GridPosition]+findPositions pred = V.toList . V.concat . V.toList . V.map (\(i,r) -> V.map (i,) . V.findIndices (pred . unwrap) . elements $ r) . indexed . rows+++-- | A monad for examining a grid.++newtype GridExamine e a = GridExamine (StateT GridPosition (Reader (Grid e)) a)+ deriving (Functor, Applicative, Monad)++-- | Run a grid examination. A start position must be specified.++gridExamine :: Grid e -> GridPosition -> GridExamine e a -> a+gridExamine grid start (GridExamine s) = runReader (evalStateT s start) grid++-- | Get the entire grid.++getGrid :: GridExamine e (Grid e)+getGrid = GridExamine (lift ask)++-- | Get the current position in the grid.++getPosition :: GridExamine e GridPosition+getPosition = GridExamine get++-- | Set the current position in the grid. +-- This is unsafe -- an in bounds check is NOT performed.++putPosition :: GridPosition -> GridExamine e ()+putPosition = GridExamine . put++-- | Modify the current position in the grid.+-- This is unsafe -- an in bounds check is NOT performed.++modifyPosition :: (GridPosition -> GridPosition) -> GridExamine e ()+modifyPosition f = GridExamine (St.modify f)++here :: GridExamine e (Maybe (GridElem e))+here = do+ grid <- getGrid+ (rowPos, elemPos) <- getPosition+ return $ do+ row <- rows grid !? rowPos+ element <- elements row !? elemPos+ return element++-- | Get the element at the current position.++hereGet :: GridExamine e (Maybe e)+hereGet = do+ element <- here+ return $ fmap unwrap element++-- | Move to and return the grid element to the left. If there is no element to +-- the left, returns Nothing.++leftGet :: GridExamine e (Maybe e)+leftGet = do+ (rowPos, elemPos) <- getPosition+ if elemPos > 0 + then putPosition (rowPos, elemPos - 1) >> (hereGet)+ else return Nothing++-- | Move to and return the grid element to the right. If there is no element to +-- the right, returns Nothing.++rightGet :: GridExamine e (Maybe e)+rightGet = do+ grid <- getGrid+ (rowPos, elemPos) <- getPosition+ fromMaybe (return Nothing) $ do+ row <- rows grid !? elemPos + element <- elements row !? (elemPos + 1)+ return $ putPosition (rowPos, elemPos + 1) >> return (Just $ unwrap element)++-- | Move to and return the grid element above the column a certain distance +-- from the right edge of the current element. If there is no such element, returns +-- Nothing.++rUpGet :: Int -> GridExamine e (Maybe e)+rUpGet n = do+ grid <- getGrid+ mCurrentElement <- here+ (rowPos, _) <- getPosition+ fromMaybe (return Nothing) $ do+ currentElement <- mCurrentElement+ newRow <- rows grid !? (rowPos - 1)+ i <- fromLeft newRow (end currentElement - 1 - n)+ return $ putPosition (rowPos - 1, i) >> hereGet++-- | Move to and return the grid element below the column a certain distance +-- from the right edge of the current element. If there is no such element, returns +-- Nothing.++rDownGet :: Int -> GridExamine e (Maybe e)+rDownGet n = do+ grid <- getGrid+ mCurrentElement <- here+ (rowPos, _) <- getPosition+ fromMaybe (return Nothing) $ do+ currentElement <- mCurrentElement+ newRow <- rows grid !? (rowPos + 1)+ i <- fromLeft newRow (end currentElement - 1 - n)+ return $ putPosition (rowPos + 1, i) >> hereGet++-- | Move to and return the grid element above the column a certain distance +-- from the left edge of the current element. If there is no such element, returns +-- Nothing.++lUpGet :: Int -> GridExamine e (Maybe e)+lUpGet n = do+ grid <- getGrid+ (rowPos, elemPos) <- getPosition+ fromMaybe (return Nothing) $ do+ row <- rows grid !? rowPos+ let start = fromMaybe 0 $ end <$> (elements row !? (elemPos - 1))+ newRow <- rows grid !? (rowPos - 1)+ i <- fromLeft newRow (start + n)+ return $ putPosition (rowPos - 1, i) >> hereGet++-- | Move to and return the grid element below the column a certain distance +-- from the left edge of the current element. If there is no such element, returns +-- Nothing.++lDownGet :: Int -> GridExamine e (Maybe e)+lDownGet n = do+ grid <- getGrid+ (rowPos, elemPos) <- getPosition+ fromMaybe (return Nothing) $ do+ row <- rows grid !? rowPos+ let start = fromMaybe 0 $ end <$> (elements row !? (elemPos - 1))+ newRow <- rows grid !? (rowPos + 1)+ i <- fromLeft newRow (start + n)+ return $ putPosition (rowPos + 1, i) >> hereGet++-- | Branch an examination, i.e. perform it and then return to the original position.++branch :: GridExamine e a -> GridExamine e a+branch ge = do+ pos <- getPosition+ x <- ge+ putPosition pos+ return x++-- | The width of the current element++width :: GridExamine e (Maybe Int)+width = do+ grid <- getGrid+ (rowPos, elemPos) <- getPosition+ mh <- here+ return $ do+ h <- mh+ row <- rows grid !? rowPos+ let start = fromMaybe 0 $ end <$> (elements row !? (elemPos - 1))+ return (end h - start)
+ Control/Arrow/Needle/Parse.hs view
@@ -0,0 +1,308 @@+{-|+Module : Control.Arrow.Needle.Parse+Description : Parsing needle diagrams+Copyright : (c) 2014 Josh Kirklin+License : MIT+Maintainer : jjvk2@cam.ac.uk++This module's main export is 'parseNeedle', which parses a needle diagram into a `NeedleArrow`.+-}++module Control.Arrow.Needle.Parse (+ -- * Parsing needles+ NeedleArrow (..)+ , parseNeedle+ -- * Errors+ , NeedleError (..)+ , presentNeedleError+ ) where++import qualified Data.Map.Strict as M++import qualified Data.Text as T+import Data.Maybe+import Data.Either+import Data.Monoid++import Text.Parsec as P+import Text.Parsec.Extra (natural)+import Data.Char++import Control.Monad+import Control.Applicative ((<$>), (<*>))+import Control.Monad.State+import Control.Arrow++import Control.Arrow.Needle.Internal.UnevenGrid as G++--------------------------------+-- Types+--------------------------------++-- | The datatype representing a generic needle arrow.++data NeedleArrow = Input Int Int+ | Through NeedleArrow T.Text+ | Join [NeedleArrow]+ deriving (Show, Read, Eq)++-- | The grid element for the first round of parsing.++data NeedleElem = None+ | Track+ | In Int Int+ | Out+ | LabelIn T.Text+ | LabelOut T.Text+ | ExtArrow T.Text+ | Switch Direction+ | TunnelEntrance+ | TunnelExit+ deriving (Show, Read, Eq)++-- | Errors in parsing.++data NeedleError = ParseError String+ | ConstructionError String++instance Show NeedleError where+ show = presentNeedleError++-- | Present the error.++presentNeedleError :: NeedleError -> String+presentNeedleError (ParseError s) = "Needle parse error:\n"++s+presentNeedleError (ConstructionError s) = "Needle construction error:\n"++s++data Direction = Up | Down+ deriving (Show, Read, Eq)++type NeedleGrid = Grid NeedleElem++--------------------------------+-- String -> NeedleArrow+--------------------------------++-- | Parse a string to a needle++parseNeedle :: String -> Either NeedleError NeedleArrow+parseNeedle = parseNeedleGrid >=> gridArrow++--------------------------------+-- NeedleGrid -> NeedleArrow+--------------------------------++gridArrow :: NeedleGrid -> Either NeedleError NeedleArrow+gridArrow grid = do+ os <- mapM (arrowToPosition grid) $ outputPositions grid+ maybe (Left $ ConstructionError "No outputs") return $ arrowJoin os++outputPositions :: NeedleGrid -> [GridPosition]+outputPositions = findPositions (== Out)++findLabelOutPosition :: T.Text -> GridExamine NeedleElem (Maybe GridPosition)+findLabelOutPosition t = do+ grid <- getGrid+ return $ listToMaybe (findPositions (== (LabelOut t)) grid)++arrowJoin :: [NeedleArrow] -> Maybe NeedleArrow+arrowJoin [] = Nothing+arrowJoin [a] = Just a+arrowJoin as = Just $ Join as++arrowToPosition :: NeedleGrid -> GridPosition -> Either NeedleError NeedleArrow+arrowToPosition grid pos = gridExamine grid pos go+ where+ err = return . Left . ConstructionError+ success = return . Right+ + tryPath path = branch $ do+ mp <- path+ case mp of+ Nothing -> err "Nothing on this path"+ Just _ -> go++ go = do+ mh <- hereGet+ case mh of+ Nothing -> err "Position not in grid"+ Just h -> case h of+ None -> err "Arrow from nothing"+ Track -> do+ w <- fromJust <$> width+ ups <- forM [0 .. (w - 1)] $ \n -> tryPath $ do+ e <- lUpGet n+ return $ mfilter (== (Switch Down)) e+ downs <- forM [0 .. (w - 1)] $ \n -> tryPath $ do+ e <- lDownGet n+ return $ mfilter (== (Switch Up)) e+ left <- tryPath leftGet+ let paths = rights $ left : ups ++ downs+ mJoint = arrowJoin paths+ case mJoint of+ Nothing -> do+ (n, _) <- G.getPosition+ err $ "Track from nowhere on line " ++ show (n + 1)+ Just joint -> success joint+ In n m -> success $ Input n m+ Out -> do+ ml <- leftGet+ case ml of+ Just l -> go+ Nothing -> err "An output has no arrow going into it"+ LabelIn t -> do+ mlo <- findLabelOutPosition t+ case mlo of+ Just lo -> putPosition lo >> go+ Nothing -> err $ "Found label-in '" ++ T.unpack t ++ "' with no label-out"+ LabelOut t -> do+ ml <- leftGet+ case ml of+ Just l -> go+ Nothing -> err $ "Label-out '" ++ T.unpack t ++ "' has no arrow going into it"+ ExtArrow t -> do+ left <- tryPath leftGet+ up <- tryPath $ do+ e <- lUpGet 0+ return $ mfilter (== (Switch Down)) e+ down <- tryPath $ do+ e <- lDownGet 0+ return $ mfilter (== (Switch Up)) e+ let paths = rights $ [left,up,down]+ mJoint = arrowJoin paths+ case mJoint of+ Nothing -> do+ (n, _) <- G.getPosition+ err $ "External arrow '" ++ T.unpack t ++ "' on line " ++ show (n + 1) ++ " has no arrow going into it"+ Just joint -> success $ Through joint t+ Switch d -> do+ left <- tryPath leftGet+ continuing <- tryPath $ do+ e <- case d of+ Down -> lUpGet 0+ Up -> lDownGet 0+ return $ mfilter (== h) e+ let paths = rights $ [left, continuing]+ mJoint = arrowJoin paths+ case mJoint of+ Nothing -> do+ (n, _) <- G.getPosition+ err $ "Line switch from nowhere on line " ++ (show n)+ Just joint -> success joint+ TunnelExit -> do+ let tunnel n = if n == 0 + then go+ else do+ ml <- leftGet+ case ml of+ Nothing -> do+ (n,_) <- G.getPosition+ err $ "Tunnel from nowhere on line " ++ (show n)+ Just TunnelExit -> tunnel (n+1)+ Just TunnelEntrance -> tunnel (n-1)+ Just _ -> tunnel n+ tunnel 1+ TunnelEntrance -> do+ ml <- leftGet+ case ml of+ Nothing -> do+ (n,_) <- G.getPosition+ err $ "Tunnel entrance has no arrow going into it on line " ++ (show n)+ Just _ -> go++--------------------------------+-- String -> NeedleGrid+--------------------------------++-- | Pretty print a needle grid++prettyNeedleGrid :: NeedleGrid -> String+prettyNeedleGrid = prettyGrid prettyElem+ where+ prettyElem None n = replicate n ' '+ prettyElem Track n = replicate n '='+ prettyElem (In _ _) n = replicate (n-1) ' ' ++ "}"+ prettyElem Out n = ">" ++ replicate (n-1) ' '+ prettyElem (LabelIn t) n = replicate (n - 1 - length s) ' ' ++ s ++ ":"+ where + s = T.unpack t+ prettyElem (LabelOut t) n = ":" ++ s ++ replicate (n - 1 - length s) ' ' + where + s = T.unpack t+ prettyElem (ExtArrow t) n = "{" ++ s ++ replicate (n - 2 - length s) ' ' ++ "}"+ where+ s = T.unpack t+ prettyElem (Switch Up) n = replicate n '/'+ prettyElem (Switch Down) n = replicate n '\\'+ prettyElem TunnelEntrance n = replicate n ')'+ prettyElem TunnelExit n = replicate n '('++-- | Parse a needle grid++parseNeedleGrid :: String -> Either NeedleError NeedleGrid+parseNeedleGrid s = case result of+ Left pe -> Left . ParseError $+ "line " ++ (show . sourceLine . errorPos $ pe) ++ ":\n" +++ ls !! ((sourceLine . errorPos $ pe) - 1) ++ "\n" +++ replicate ((sourceColumn . errorPos $ pe) - 1) ' ' ++ "^"+ Right x -> Right (grid x)+ where+ result = zipWithM parseLine ls [1..]+ ls = lines s+ parseLine l n = runParser (do+ p <- P.getPosition+ setPosition $ setSourceLine p n+ es <- many (withWidth . choice . map try $ elemParsers n)+ optional $ try (string "-- " >> many anyChar)+ eof+ return es) 0 "needle expression" l+ withWidth p = do+ c1 <- sourceColumn <$> P.getPosition+ x <- p+ c2 <- sourceColumn <$> P.getPosition+ return (x, c2 - c1)++ elemParsers n = [+ do+ many1 space+ return None+ , do+ many1 (char '=')+ return Track+ , do+ void (char '}')+ m <- getState+ modifyState (+1)+ return $ In n m+ , do+ void (char '>')+ return Out+ , do+ l <- many1 letter+ spaces+ void (char ':')+ return $ LabelIn (T.pack l)+ , do+ void (char ':')+ spaces+ l <- many1 letter+ return $ LabelOut (T.pack l)+ , do+ void (char '{')+ f <- anyChar+ l <- manyTill anyChar (char '}')+ return $ ExtArrow (T.pack $ f : l)+ , do+ void (char '/')+ return $ Switch Up+ , do+ void (char '\\')+ return $ Switch Down+ , do+ void (char ')')+ return TunnelEntrance+ , do+ void (char '(')+ return TunnelExit+ ]+
+ Control/Arrow/Needle/TH.hs view
@@ -0,0 +1,109 @@+{-|+Module : Control.Arrow.Needle.TH+Description : Template Haskell for needle+Copyright : (c) 2014 Josh Kirklin+License : MIT+Maintainer : jjvk2@cam.ac.uk++This module combines the parsing from "Control.Arrow.Needle.Parse" with Template Haskell.+-}++{-# LANGUAGE TemplateHaskell, TupleSections #-}++module Control.Arrow.Needle.TH (+ nd+ , ndFile+ ) where++import Prelude as Pre++import Control.Arrow.Needle.Parse+import Control.Arrow++import Control.Applicative++import Language.Haskell.TH+import Language.Haskell.TH.Quote+import Language.Haskell.Meta++import Data.Either+import Data.Text as T+import Data.Map.Strict as M++-- | The inline needle quasi-quoter.+--+-- > {-# LANGUAGE QuasiQuotes #-}+-- > +-- > exampleArrow :: Num c => (a,b,c) -> (a,a,b,c,c)+-- > exampleArrow = [nd|+-- > }===========>+-- > \========>+-- > }===========>+-- > }==={negate}>+-- > \========>+-- > |]++nd :: QuasiQuoter+nd = QuasiQuoter { + quoteExp = \str -> case (parseNeedle str) of+ Left e -> error . presentNeedleError $ e+ Right n -> arrowQ n+ , quotePat = error "Needles cannot be patterns."+ , quoteDec = error "Needles cannot be declarations."+ , quoteType = error "Needles cannot be types."+ }++-- | Load a needle from a file.+--+-- > {-# LANGUAGE TemplateHaskell #-}+-- > +-- > exampleArrow :: Float -> Float+-- > exampleArrow = $(ndFile "example.nd")++ndFile :: FilePath -> ExpQ+ndFile fp = do+ str <- runIO $ readFile fp+ case (parseNeedle str) of+ Left e -> error . presentNeedleError $ e+ Right n -> arrowQ n++-- | Convert NeedleArrow to ExpQ++arrowQ :: NeedleArrow -> ExpQ+arrowQ arrow = do+ let is = inputs arrow+ iNameMap <- M.fromList <$> mapM (\(a,b) -> ((a,b),) <$> newName ("_" ++ show a ++ "_" ++ show b)) is++ let iNames = Pre.map snd $ M.toList iNameMap+ iName (Input a b) = iNameMap ! (a,b)++ f i@(Input a b) = return + $ AppE (VarE $ mkName "arr") + $ LamE [TupP $ Pre.map VarP iNames] (VarE (iName i))++ f (Through a t) = do+ let ea = either error id $ parseExp . T.unpack $ t+ b <- f a+ return $ InfixE (Just b) (VarE $ mkName ">>>") (Just ea)++ f (Join as) = do+ aNames <- mapM (\n -> newName ("_" ++ show n)) [0..(Pre.length as - 1)]+ + let tupleArrows [c] = f c+ tupleArrows (c:cs) = [| $(f c) &&& $(tupleArrows cs) |]++ tupleNames [n] = VarP n+ tupleNames (n:ns) = TupP [VarP n, tupleNames ns]++ b <- tupleArrows as++ return $ InfixE (Just b) (VarE $ mkName ">>>") $ Just+ $ AppE (VarE $ mkName "arr") + $ LamE [tupleNames aNames] (TupE $ Pre.map VarE aNames)++ f arrow++inputs :: NeedleArrow -> [(Int, Int)]+inputs (Input a b) = [(a,b)]+inputs (Through a _) = inputs a+inputs (Join as) = as >>= inputs
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2014 Josh Kirklin++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ needle.cabal view
@@ -0,0 +1,34 @@+name: needle+version: 0.1.0.0+synopsis: ASCII-fied arrow notation+description: Needle is a domain specific language for ASCII-fied arrow notation. See "Control.Arrow.Needle" for more information and an example.+license: MIT+license-file: LICENSE+author: Josh Kirklin+maintainer: Josh Kirklin <jjvk2@cam.ac.uk>+copyright: (c) 2014 Josh Kirklin+category: Control+build-type: Simple+stability: experimental+bug-reports: https://github.com/ScrambledEggsOnToast/needle/issues+cabal-version: >=1.10++library+ exposed-modules: Control.Arrow.Needle+ Control.Arrow.Needle.Parse+ Control.Arrow.Needle.TH+ other-modules: Control.Arrow.Needle.Internal.UnevenGrid+ build-depends: base >=4.7 && <4.8+ , text >=1.2 && <1.3+ , parsec >= 3.1 && <3.2+ , parsec-extra >=0.1 && <0.2+ , containers >=0.5 && <0.6+ , mtl >=2.2 && <2.3+ , template-haskell+ , haskell-src-meta >=0.6 && <0.7+ , vector >= 0.10 && <0.11+ default-language: Haskell2010++source-repository head+ type: git+ location: git://github.com/ScrambledEggsOnToast/needle.git