packages feed

flexiwrap-0.0.1: Data/Flex/Examples/Lex/Strict.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -fcontext-stack=25 #-}
-- .$Header: c:/Source/Haskell/Wrapper/Data/Flex/Examples/Lex/RCS/Strict.hs,v 1.8 2011/02/16 00:58:48 dosuser Exp dosuser $
module Data.Flex.Examples.Lex.Strict where

import Control.Applicative (Applicative(..), (<$>), Alternative(..),
        liftA2
    )
import Control.Monad (join, ap, liftM, MonadPlus(..))
import Control.Monad.State (
        StateT(..), MonadState(..), modify, gets, evalStateT
    )
import Control.Monad.Trans (MonadTrans(..))

import Data.Char (ord)
import Data.Foldable as F (Foldable(..))
import Data.Maybe (fromJust)
-- isJust, catMaybes,
import Data.List (delete)

import Data.Flex.Compose ((:.)(..), O,
        FWCompP, FWCompS, FWCompDefaults, FWCompMonadPlusL
    )
import Data.Flex.FlipT (FlipT(..), FWFlipDefaults, FWFlipMonad)
import Data.Flex.Wrap (FW, FlexiWrap(..))
import Data.Flex.WrapCTC (FlexiWrapCTC(..), FWCTC)
import Data.Flex.WrappedMonad (FWMonadApplicative, FWWrapMonad)
import Data.Flex.WrapT (FlexiWrapT(..), FWT, inFlexiWrapT2, FWTDefaultMonadAll)

import Data.Flex.Examples.Lex.Simple

import Data.Type.TList

import Test.QuickCheck

data FWStrict = FWStrict

type Strict = FW (FWStrict :*: TNil)

strict :: a -> Strict a
strict = FlexiWrap

type StrictT = FWCTC
    (FWFlipDefaults :*:
        FWCompMonadPlusL :*: FWCompDefaults :*: FWCompS :*: TNil
    )
    (FlipT O) Strict

strictT :: f (Strict a) -> StrictT f a
strictT = FlexiWrapCTC . FlipT . O

unStrictT :: StrictT f a -> f (Strict a)
unStrictT = unO . unFlipT . unFlexiWrapCTC

type MaybeT = FWCTC
    (FWFlipDefaults :*: FWCompDefaults :*: FWCompP :*: TNil)
    (FlipT O) Maybe

-- maybeT :: Monad f => f (Maybe a) -> MaybeT f a
maybeT :: f (Maybe a) -> MaybeT f a
maybeT = FlexiWrapCTC . FlipT . O

unMaybeT :: MaybeT f a -> f (Maybe a)
unMaybeT = unO . unFlipT . unFlexiWrapCTC

type StrictMaybeT f = StrictT (MaybeT f)

{-
    StrictMaybeT f x ==
    StrictT (MaybeT f) x ==
    FWCTC tag (FlipT O) Strict (MaybeT f) x ~
    O (MaybeT f) Strict x ~
    MaybeT f (Strict x) ==
    FWCTC tag (FlipT O) Maybe f (Strict x) ~
    O f Maybe (Strict x) ~
    f (Maybe (Strict x))
-}

type WStateT s m =
    FWT (FWWrapMonad :*: FWTDefaultMonadAll :*: TNil) (StateT s m)

type StrictMaybeStateGen s = WStateT s (StrictMaybeT Gen)

{-
instance Monad m => Applicative (WStateT s m) where
    pure = FlexiWrapT . return
    (<*>) = inFlexiWrapT2 ap
-}

-- instance (MonadPlus m, Applicative (WStateT s m)) =>
instance MonadPlus m =>
        Alternative (WStateT s m) where
    empty = FlexiWrapT . StateT $ \s -> flip (,) s `liftM` mzero
    -- a <|> b = (<|>) <$> a <*> b
    a <|> b = FlexiWrapT . StateT $ \s ->
        runStateT (unFlexiWrapT a) s `mplus` runStateT (unFlexiWrapT b) s

{-
-- instance (Monad m, Monad (WStateT s m)) => MonadState s (WStateT s m) where
instance Monad m => MonadState s (WStateT s m) where
        -- and/or Monad (WStateT s m), Monad m
    get = lift get
    put = lift . put
-}

-- class Monad m => MonadGen m where
class MonadGen m where
    liftGen :: Gen a -> m a

instance MonadGen Gen where
    liftGen = id

-- instance (MonadTrans t, MonadGen m, Monad (t m)) => MonadGen (t m) where
instance (MonadTrans t, Monad m, MonadGen m) => MonadGen (t m) where
    liftGen = lift . liftGen

{-
-- instance (MonadGen m, Monad (WStateT s m)) =>  MonadGen (WStateT s m) where
instance (Monad m, MonadGen m) =>  MonadGen (WStateT s m) where
    liftGen = lift . lift . liftGen
-}

class MonadMaybe m where
    liftMaybe :: Maybe a -> m a

instance MonadMaybe Maybe where
    liftMaybe = id

instance Monad m => MonadMaybe (MaybeT m) where
    liftMaybe = maybeT . return

instance (Monad m, MonadMaybe m) => MonadMaybe (StrictT m) where
    liftMaybe = lift . liftMaybe

instance (Monad m, MonadMaybe m) => MonadMaybe (WStateT s m) where
    liftMaybe = lift . lift . liftMaybe

lexAlphabet = "abcde"
lexIndex :: Char -> Int
lexIndex c
    | 'a' <= c && c <= 'e' = ord c - ord 'a'
    | otherwise = error "lexAlphabet character out of range"

-- strictMaybeBasic :: (Eq c, MonadState [c] (StrictMaybeStateGen [c])) =>
strictMaybeBasic :: Eq c =>
    StrictMaybeStateGen [c] (Basic c)
strictMaybeBasic = do
    c <- join $ gets select
    modify $ delete c
    return $ BSimple c
 where
    -- select :: (Eq c, Monad (StrictMaybeStateGen [c])) =>
    -- select :: Eq c =>
    select ::
        [c] -> StrictMaybeStateGen [c] c
    select [] = liftMaybe Nothing
    select l = liftGen $ elements l

{-
-- This clashes with any generic Arbitrary (Maybe a) instance
instance Arbitrary (Maybe (Strict (Basic Char))) where
    arbitrary = unMaybeT . unStrictT $ evalStateT strictMaybeBasic lexAlphabet
    coarbitrary Nothing = variant 0
    coarbitrary (Just (FlexiWrap (BSimple c))) = variant $ 1 + lexIndex c
-}

instance Arbitrary ((Maybe :. Strict) (Basic Char)) where
    arbitrary = fmap O . unMaybeT . unStrictT $
        evalStateT (unFlexiWrapT strictMaybeBasic) lexAlphabet
    coarbitrary (O Nothing) = variant 0
    coarbitrary (O (Just (FlexiWrap (BSimple c)))) = variant $ 1 + lexIndex c

{-
sizedStrictMaybeBSingle :: (
        Eq c, Applicative (StrictMaybeStateGen [c]),
        Monad (StrictMaybeStateGen [c])
    ) =>
-}
sizedStrictMaybeBSingle :: Eq c => Int -> StrictMaybeStateGen [c] (Single c)
sizedStrictMaybeBSingle 0 = SSimple <$> strictMaybeBasic
sizedStrictMaybeBSingle n | n > 0 =
    (SOr <$> strictMaybeBasic <*> sizedStrictMaybeBSingle (n - 1))
    <|>
    sizedStrictMaybeBSingle 0

{-
-- This clashes with any generic Arbitrary (Maybe a) instance
instance Arbitrary (Maybe (Strict (Single Char))) where
    arbitrary = sized $ unMaybeT . unStrictT .
        flip evalStateT lexAlphabet . unFlexiWrapT . sizedStrictMaybeBSingle
    coarbitrary Nothing = variant 0
    coarbitrary (Just (FlexiWrap (SSimple b))) =
        variant 1 . coarbitrary (O . Just $ strict b)
    coarbitrary (Just (FlexiWrap (b `SOr` c))) = variant 2 .
        coarbitrary (O . Just $ strict b) . coarbitrary (O . Just $ strict c)
-}

instance Arbitrary ((Maybe :. Strict) (Single Char)) where
    arbitrary = fmap O . sized $ unMaybeT . unStrictT .
        flip evalStateT lexAlphabet . unFlexiWrapT . sizedStrictMaybeBSingle
    coarbitrary (O Nothing) = variant 0
    coarbitrary (O (Just (FlexiWrap (SSimple b)))) =
        variant 1 . coarbitrary (O . Just $ strict b)
    coarbitrary (O (Just (FlexiWrap (b `SOr` c)))) = variant 2 .
        coarbitrary (O . Just $ strict b) . coarbitrary (O . Just $ strict c)

liftStrictMaybe :: (
            MonadTrans t, MonadTrans u, Monad f, Monad (u (StrictT (MaybeT f)))
        ) =>
    f (Maybe (Strict a)) -> t (u (StrictT (MaybeT f))) a
liftStrictMaybe = lift . lift . strictT . maybeT

{-
sizedStrictMaybeSimple :: (Eq c,
        -- Arbitrary (Maybe (Strict s))
        Arbitrary (Strict s),
        Applicative (StrictMaybeStateGen [c]),
        Monad (StrictMaybeStateGen [c])
    ) =>
-}
sizedStrictMaybeSimple :: (Eq c,
        -- Arbitrary (Maybe (Strict s))
        Arbitrary (Strict s)
    ) =>
    Int -> StrictMaybeStateGen [c] (Simple s c)
sizedStrictMaybeSimple n = TSimple <$> sizedStrictMaybeBSingle n2 <*>
    liftStrictMaybe (fmap Just $ resize n2 arbitrary)
  where n2 = n `div` 2

{-
-- This clashes with any generic Arbitrary (Maybe a) instance
instance
    -- Arbitrary (Maybe (Strict s))
    Arbitrary (Strict s)
  =>
    Arbitrary (Maybe (Strict (Simple s Char)))
  where
    arbitrary = sized $ unMaybeT . unStrictT .
        flip evalStateT lexAlphabet . sizedStrictMaybeSimple
    coarbitrary Nothing = variant 0
    coarbitrary (Just (FlexiWrap (TSimple b l))) = variant 1 .
        coarbitrary (O . Just $ strict b) . coarbitrary (strict l)
-}

instance
    Arbitrary (Strict s)
  =>
    Arbitrary ((Maybe :. Strict) (Simple s Char))
  where
    arbitrary = fmap O . sized $ unMaybeT . unStrictT .
        flip evalStateT lexAlphabet . unFlexiWrapT . sizedStrictMaybeSimple
    coarbitrary (O Nothing) = variant 0
    coarbitrary (O (Just (FlexiWrap (TSimple b l)))) = variant 1 .
        coarbitrary (O . Just $ strict b) . coarbitrary (strict l)

{-
sizedStrictMaybeLex :: (
        Eq c, Arbitrary a,
        -- Arbitrary (Maybe (Strict (Lex c a)))
        Arbitrary (Strict (Lex c a)),
        Applicative (StrictMaybeStateGen [c]),
        Monad (StrictMaybeStateGen [c])
    ) =>
-}
sizedStrictMaybeLex :: (
        Eq c, Arbitrary a,
        -- Arbitrary (Maybe (Strict (Lex c a)))
        Arbitrary (Strict (Lex c a))
    ) =>
    Int -> StrictMaybeStateGen [c] (Lex c a)
sizedStrictMaybeLex 0 = sequence [
        return LNil
        , LDone <$> liftGen arbitrary
    ] >>= liftGen . elements
sizedStrictMaybeLex n | n > 0 = catAlternatives [
        LRepeat . SRepeat <$> sizedStrictMaybeSimple (n - 1)
        , LOr . SOnce <$> sizedStrictMaybeSimple n2 <*>
            sizedStrictMaybeLex n2
    ] >>= select
  where
    n2 = n `div` 2
    select [] = sizedStrictMaybeLex 0
    select l = liftGen $ elements l

catAlternatives :: (Foldable f, Alternative g) => f (g b) -> g [b]
catAlternatives = F.foldr merge (pure []) where
    merge b bs = liftA2 (:) b bs <|> bs

instance Arbitrary a => Arbitrary (Strict (Lex Char a)) where
    arbitrary = alphabetSizedStrictLex lexAlphabet
    coarbitrary (FlexiWrap LNil) = variant 0
    coarbitrary (FlexiWrap (LDone a)) = variant 1 . coarbitrary a
    coarbitrary (FlexiWrap (LRepeat (SRepeat s))) = variant 2 .
        coarbitrary (O . Just $ strict s)
    coarbitrary (FlexiWrap (SOnce s `LOr` l)) = variant 3 .
        coarbitrary (O . Just $ strict s) . coarbitrary (strict l)

{-
alphabetSizedStrictLex :: (
        Eq c, Arbitrary a,
        -- Arbitrary (Maybe (Strict (Lex c a)))
        Arbitrary (Strict (Lex c a)),
        Applicative (StrictMaybeStateGen [c]),
        Monad (StrictMaybeStateGen [c])
    ) =>
-}
alphabetSizedStrictLex :: (
        Eq c, Arbitrary a,
        -- Arbitrary (Maybe (Strict (Lex c a)))
        Arbitrary (Strict (Lex c a))
    ) =>
    [c] -> Gen (Strict (Lex c a))
alphabetSizedStrictLex alphabet = sized $ fmap fromJust .
    unMaybeT . unStrictT . flip evalStateT alphabet .
    unFlexiWrapT . sizedStrictMaybeLex

-- vim: expandtab:tabstop=4:shiftwidth=4