packages feed

free-operational 0.2.0.0 → 0.3.0.0

raw patch · 4 files changed

+176/−19 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Control.Alternative.Operational: (:<|>) :: ProgramViewAlt instr a -> ProgramViewAlt instr a -> ProgramViewAlt instr a
- Control.Alternative.Operational: Empty :: ProgramViewAlt instr a
- Control.Applicative.Operational: compile :: ProgramViewAp instr a -> ProgramAp instr a
- Control.MonadPlus.Operational: MEmpty :: ProgramViewP instr a
+ Control.Alternative.Operational: Many :: [ProgramViewAlt instr a] -> ProgramViewAlt instr a
+ Control.Alternative.Operational: compileAlt :: ProgramViewAlt instr a -> ProgramAlt instr a
+ Control.Alternative.Operational: foldProgramViewAlt :: (forall x. instr x -> r -> r) -> r -> ([r] -> r) -> ProgramViewAlt instr a -> r
+ Control.Applicative.Operational: compileAp :: ProgramViewAp instr a -> ProgramAp instr a
- Control.MonadPlus.Operational: MPlus :: ProgramViewP instr a -> ProgramViewP instr a -> ProgramViewP instr a
+ Control.MonadPlus.Operational: MPlus :: [ProgramViewP instr a] -> ProgramViewP instr a

Files

Control/Alternative/Operational.hs view
@@ -5,6 +5,151 @@ -- | @operational@-style 'Alternative' programs.  See -- "Control.Applicative.Operational" for guidance on how to use this -- module.+--+-- Example: simple applicative parsers:+--+-- > import Control.Applicative+-- > import Control.Alternative.Operational+-- > import Control.Alternative.Monad (void)+-- > import Data.Functor.Compose (Compose(..))+-- > import Data.Traversable+-- > import Data.Maybe (listToMaybe)+-- > data ParserI a where+-- >     Symbol :: Char -> ParserI Char+-- > +-- > char :: Operational ParserI f => Char -> f Char+-- > char = singleton . Symbol+-- > +-- > string :: (Operational ParserI f, Applicative f) => String -> f String+-- > string = traverse char+-- > +-- > oneOf :: (Operational ParserI f, Alternative f) => String -> f Char+-- > oneOf = foldr (<|>) empty . map char+-- > +-- > +-- > -- | Example parser: match parentheses and count depth.+-- > parens :: ProgramAlt ParserI Int+-- > parens = pure 0  <|>  char '(' *> fmap (+1) parens <* char ')'+-- > +-- > +-- > -- | Interpret a parser program \"syntactically\" by pattern matching+-- > -- on its view.+-- > runParser :: ProgramAlt ParserI a -> String -> Maybe a+-- > runParser = fmap listToMaybe . eval . viewAlt+-- >     where+-- >       eval :: ProgramViewAlt ParserI a -> String -> [a]+-- >       eval (Pure a) [] = pure a+-- >       eval (Pure a) _  = empty+-- >       eval (Symbol c :<**> k) [] = empty+-- >       eval (Symbol c :<**> k) (x:xs) +-- >           | c == x    = pure c <**> eval k xs+-- >           | otherwise = empty+-- >       eval (Many ps) str = fmap asum (sequenceA (map eval ps)) str+-- > +-- > asum :: Alternative f => [f a] -> f a+-- > asum = foldr (<|>) empty+--+-- Alternatively, programs may be interpreted in a more denotational+-- style:+--+-- > runParser :: ProgramAlt ParserI a -> String -> Maybe a+-- > runParser = (firstSuccess .) . runStateT . interpretAlt evalParserI+-- >     where firstSuccess [] = Nothing+-- >           firstSuccess ((a,""):_) = Just a+-- >           firstSuccess (_:xs) = firstSuccess xs+-- > +-- > evalParserI :: ParserI a -> StateT String [] a+-- > evalParserI (Symbol c) = +-- >     do str <- get+-- >        case str of+-- >          x:xs | c == x -> put xs >> return c+-- >          otherwise     -> mzero+--+-- One of the big \"powers\" of 'ProgramAlt' is that it allows for+-- powerful static analysis of programs.  For example, we can+-- enumerate the strings accepted by a non-degenerate parser:+--+-- > -- | Static analysis example: enumerate the strings accepted by a parser.+-- > enumerate :: ProgramAlt ParserI a -> [String]+-- > enumerate = go [showString ""] . viewAlt+-- >     where+-- >       go :: [ShowS] -> ProgramViewAlt ParserI a -> [String]+-- >       go strs (Pure a) = map ($"") strs+-- >       go strs (Symbol c :<**> k) = go (map (.(showChar c)) strs) k+-- >       go strs (Many ps) = interleave $ map (go strs) ps+-- > +-- > interleave :: [[a]] -> [a]+-- > interleave = foldr interleave2 []+-- >     where+-- >       interleave2 :: [a] -> [a] -> [a]+-- >       interleave2 [] ys = ys+-- >       interleave2 (x:xs) ys = x : interleave2 ys xs+--+-- >>> take 7 (enumerate parens)+-- ["","()","(())","((()))","(((())))","((((()))))","(((((())))))"]+-- +-- (@enumerate@ isn't guaranteed to terminate or even produce WHNF for+-- all parsers; e.g., @let a = char 'a' *> a in enumerate a@+-- diverges.  But this parser doesn't accept any strings!)+--+-- Or we can optimize a (non-degenerate) parser by merging prefixes:+--+-- > optimize :: ProgramAlt ParserI a -> ProgramAlt ParserI a+-- > optimize = compileAlt . merge . viewAlt+-- > +-- > merge :: ProgramViewAlt ParserI a -> ProgramViewAlt ParserI a+-- > merge p@(Pure _) = p+-- > merge (Symbol a :<**> k) = Symbol a :<**> merge k+-- > merge (Many ps) = Many (mergeMany ps)+-- > +-- > mergeMany :: [ProgramViewAlt ParserI a] -> [ProgramViewAlt ParserI a]+-- > mergeMany = foldr step [] . map merge+-- >     where step (Pure a) ps = Pure a : ps+-- >           step (Symbol a :<**> l) ((Symbol b :<**> r) : ps) =+-- >                case a `compare` b of+-- >                  EQ -> (Symbol a :<**> Many (mergeMany [l, r])) : ps+-- >                  LT -> (Symbol a :<**> l) : (Symbol b :<**> r) : ps+-- >                  GT -> (Symbol b :<**> r) : (Symbol a :<**> l) : ps+-- >           step (Symbol a :<**> l) ps = (Symbol a :<**> l) : ps+-- >           step (Many ps) ps' = mergeMany (mergeMany ps ++ ps')+--+-- (Also not guaranteed to terminate on all cases; @let a = a <* char+-- 'a' in optimize a@ diverges, but that parser never terminates for+-- any string.)+--+-- Example of @optimize@:+--+-- > tokens :: [String] -> ProgramAlt ParserI String +-- > tokens = asum . map string+-- > +-- > example = [ "abactor", "abacus", "abaft", "abaisance", "abaissed", "abalone"+-- >           ]+-- > +-- > describe :: forall a. ProgramAlt ParserI a -> Description+-- > describe = eval . viewAlt+-- >     where eval :: forall x. ProgramViewAlt ParserI x -> Description+-- >           eval (Pure _) = Ok+-- >           eval (Symbol c :<**> k) = c :> (eval k)+-- >           eval (Many ps) = OneOf (map eval ps)+-- > +-- > data Description = Ok +-- >                  | Char :> Description+-- >                  | OneOf [Description] +-- >                    deriving Show+-- +-- >>>  describe $ tokens example+-- OneOf ['a' :> ('b' :> ('a' :> ('c' :> ('t' :> ('o' :> ('r' :> Ok)))))),+--        OneOf ['a' :> ('b' :> ('a' :> ('c' :> ('u' :> ('s' :> Ok))))),+--               OneOf ['a' :> ('b' :> ('a' :> ('f' :> ('t' :> Ok)))),+--                      OneOf ['a' :> ('b' :> ('a' :> ('i' :> ('s' :> ('a' :> ('n' :> ('c' :> ('e' :> Ok)))))))),+--                             OneOf ['a' :> ('b' :> ('a' :> ('i' :> ('s' :> ('s' :> ('e' :> ('d' :> Ok))))))),+--                                    'a' :> ('b' :> ('a' :> ('l' :> ('o' :> ('n' :> ('e' :> Ok))))))]]]]]+-- >>> describe $ optimize (tokens example)+-- 'a' :> ('b' :> ('a' :> OneOf ['c' :> OneOf ['t' :> ('o' :> ('r' :> Ok)),'u' :> ('s' :> Ok)],+--                               OneOf ['f' :> ('t' :> Ok),+--                                      OneOf ['i' :> ('s' :> OneOf ['a' :> ('n' :> ('c' :> ('e' :> Ok))),+--                                                                   's' :> ('e' :> ('d' :> Ok))]),+--                                             'l' :> ('o' :> ('n' :> ('e' :> Ok)))]]])) module Control.Alternative.Operational      ( module Control.Operational.Class     , ProgramAlt(..)@@ -13,6 +158,8 @@      , ProgramViewAlt(..)     , viewAlt+    , compileAlt+    , foldProgramViewAlt     ) where  import Control.Applicative@@ -46,14 +193,7 @@     (:<**>) :: instr a             -> ProgramViewAlt instr (a -> b)              -> ProgramViewAlt instr b-    Empty   :: ProgramViewAlt instr a-    (:<|>)  :: ProgramViewAlt instr a -            -> ProgramViewAlt instr a-            -> ProgramViewAlt instr a---- this is the same fixity as '<**>' and '<|>'; dunno why it's not infixr-infixl 4 :<**>-infixl 3 :<|>+    Many    :: [ProgramViewAlt instr a] -> ProgramViewAlt instr a  viewAlt :: ProgramAlt instr a -> ProgramViewAlt instr a viewAlt = viewAlt' . toAlt@@ -61,4 +201,21 @@ viewAlt' :: Alt (Yoneda instr) a -> ProgramViewAlt instr a viewAlt' (Free.Pure a) = Pure a viewAlt' (Free.Ap (Yoneda f i) next) = i :<**> viewAlt' (fmap (.f) next)-viewAlt' (Free.Alt xs) = foldr (:<|>) Empty (map viewAlt' xs)+viewAlt' (Free.Alt xs) = Many $ map viewAlt' xs+++compileAlt :: ProgramViewAlt instr a -> ProgramAlt instr a+compileAlt (Pure a) = pure a+compileAlt (i :<**> k) = singleton i <**> compileAlt k+compileAlt (Many xs) = foldr (<|>) empty $ map compileAlt xs++foldProgramViewAlt+    :: (forall x. instr x -> r -> r)  -- ^ ':<**>'+    -> r                              -- ^ 'Pure'+    -> ([r] -> r)                     -- ^ 'Many'+    -> ProgramViewAlt instr a+    -> r+foldProgramViewAlt k z m (Pure _) = z+foldProgramViewAlt k z m (i :<**> is) = k i (foldProgramViewAlt k z m is)+foldProgramViewAlt k z m (Many xs) = m (map subfold xs)+    where subfold = foldProgramViewAlt k z m
Control/Applicative/Operational.hs view
@@ -12,7 +12,7 @@      , ProgramViewAp(..)     , viewAp-    , compile+    , compileAp      , foldProgramViewAp     , instructions@@ -39,6 +39,8 @@ -- * <http://gergo.erdi.hu/blog/2012-12-01-static_analysis_with_applicatives/> --  -- * <http://paolocapriotti.com/blog/2013/04/03/free-applicative-functors/>+--+-- See also the examples in "Control.Alternative.Operational". newtype ProgramAp instr a =      ProgramAp { -- | Interpret a 'ProgramAp' as a free applicative ('Ap').                toAp :: Ap (Yoneda instr) a @@ -177,9 +179,9 @@ viewAp' (Free.Ap (Yoneda f i) next) = i :<**> viewAp' (fmap (.f) next)  -- | Compile a 'ProgramViewAp' back into a 'ProgramAp'.-compile :: ProgramViewAp instr a -> ProgramAp instr a-compile (Pure f) = pure f-compile (instr :<**> k) = singleton instr <**> compile k+compileAp :: ProgramViewAp instr a -> ProgramAp instr a+compileAp (Pure f) = pure f+compileAp (instr :<**> k) = singleton instr <**> compileAp k   foldProgramViewAp :: (forall x. instr x -> r -> r) 
Control/MonadPlus/Operational.hs view
@@ -45,13 +45,10 @@ data ProgramViewP instr a where     Return :: a -> ProgramViewP instr a     (:>>=) :: instr a -> (a -> ProgramP instr b) -> ProgramViewP instr b-    MEmpty :: ProgramViewP instr a-    MPlus  :: ProgramViewP instr a-           -> ProgramViewP instr a-           -> ProgramViewP instr a+    MPlus  :: [ProgramViewP instr a] -> ProgramViewP instr a  view :: ProgramP instr a -> ProgramViewP instr a view = eval . toFree      where eval (Pure a) = Return a           eval (Free (Yoneda f i)) = i :>>= (ProgramP . f)-          eval (Plus mas) = foldr MPlus MEmpty (map eval mas)+          eval (Plus mas) = MPlus $ map eval mas
free-operational.cabal view
@@ -1,6 +1,6 @@ name:                free-operational category:            Control-version:             0.2.0.0+version:             0.3.0.0 build-type:          Simple cabal-version:       >=1.8 synopsis:            Operational Applicative, Alternative, Monad and MonadPlus, built with free types.@@ -30,6 +30,7 @@     * <http://paolocapriotti.com/blog/2013/04/03/free-applicative-functors/> (discussion: <http://www.reddit.com/r/haskell/comments/1bnql3/free_applicative_functors_icfp_submission/>)     .     See "Control.Applicative.Operational" for the bulk of the documentation.+    "Control.Alternative.Operational" also has some significant examples.  license:             BSD3 license-file:        LICENSE