{-# Language Safe, RankNTypes, MultiParamTypeClasses #-}
{-# Language FunctionalDependencies #-}
{-# Language FlexibleInstances #-}
{-# Language TypeFamilies, UndecidableInstances #-}
module Cryptol.Utils.Patterns where
import Control.Monad(liftM,liftM2,ap,MonadPlus(..),guard)
import qualified Control.Monad.Fail as Fail
import Control.Applicative(Alternative(..))
newtype Match b = Match (forall r. r -> (b -> r) -> r)
instance Functor Match where
fmap = liftM
instance Applicative Match where
pure a = Match $ \_no yes -> yes a
(<*>) = ap
instance Monad Match where
Match m >>= f = Match $ \no yes -> m no $ \a ->
let Match n = f a in
n no yes
instance Fail.MonadFail Match where
fail _ = empty
instance Alternative Match where
empty = Match $ \no _ -> no
Match m <|> Match n = Match $ \no yes -> m (n no yes) yes
instance MonadPlus Match where
type Pat a b = a -> Match b
(|||) :: Pat a b -> Pat a b -> Pat a b
p ||| q = \a -> p a <|> q a
(&&&) :: Pat a b -> Pat a c -> Pat a (b,c)
p &&& q = \a -> liftM2 (,) (p a) (q a)
(~>) :: Pat a b -> (b -> c) -> Pat a c
p ~> f = \a -> f <$> p a
(~~>) :: Pat a b -> c -> Pat a c
p ~~> f = \a -> f <$ p a
(<~) :: (a -> b) -> Pat b c -> Pat a c
f <~ p = \a -> p (f a)
__ :: Pat a a
__ = return
succeed :: a -> Pat x a
succeed = const . return
checkThat :: (a -> Bool) -> Pat a ()
checkThat p = \a -> guard (p a)
lit :: Eq a => a -> Pat a ()
lit x = checkThat (x ==)
{-# Inline lit #-}
matchDefault :: a -> Match a -> a
matchDefault a (Match m) = m a id
{-# Inline matchDefault #-}
match :: Match a -> a
match m = matchDefault (error "Pattern match failure.") m
{-# Inline match #-}
matchMaybe :: Match a -> Maybe a
matchMaybe (Match m) = m Nothing Just
list :: [Pat a b] -> Pat [a] [b]
list [] = \a ->
case a of
[] -> return []
_ -> mzero
list (p : ps) = \as ->
case as of
[] -> mzero
x : xs ->
do a <- p x
bs <- list ps xs
return (a : bs)
(><) :: Pat a b -> Pat x y -> Pat (a,x) (b,y)
p >< q = \(a,x) -> do b <- p a
y <- q x
return (b,y)
class Matches thing pats res | pats -> thing res where
matches :: thing -> pats -> Match res
instance ( f ~ Pat a a1'
, a1 ~ Pat a1' r1
) => Matches a (f,a1) r1 where
matches ty (f,a1) = do a1' <- f ty
a1 a1'
instance ( op ~ Pat a (a1',a2')
, a1 ~ Pat a1' r1
, a2 ~ Pat a2' r2
) => Matches a (op,a1,a2) (r1,r2)
where
matches ty (f,a1,a2) = do (a1',a2') <- f ty
r1 <- a1 a1'
r2 <- a2 a2'
return (r1,r2)
instance ( op ~ Pat a (a1',a2',a3')
, a1 ~ Pat a1' r1
, a2 ~ Pat a2' r2
, a3 ~ Pat a3' r3
) => Matches a (op,a1,a2,a3) (r1,r2,r3) where
matches ty (f,a1,a2,a3) = do (a1',a2',a3') <- f ty
r1 <- a1 a1'
r2 <- a2 a2'
r3 <- a3 a3'
return (r1,r2,r3)