{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import Control.Applicative (Applicative(..), (<|>))
import Control.Monad (join)
import Control.Monad.Omega
import Data.List (sort)
import Prelude hiding (Applicative(..))
import Test.Tasty
import Test.Tasty.QuickCheck
main :: IO ()
main = defaultMain $ testGroup "All"
[ testProperty "pure" $ \(x :: Int) ->
sort (runOmega (pure x)) ===
sort (pure x)
, testProperty "liftA2" $ \(xs :: [Int]) ys ->
sort (runOmega (liftA2 (+) (each xs) (each ys))) ===
sort (liftA2 (+) xs ys)
, testProperty "(<|>)" $ \(xs :: [Int]) ys ->
sort (runOmega (each xs <|> each ys)) ===
sort (xs <|> ys)
, testProperty "join" $ \(xss :: [[Int]]) ->
sort (runOmega (join (each (map each xss)))) ===
sort (join xss)
, testProperty "liftA2 vs. join" $ \(xs :: [Int]) ys ->
let f x y = x * 10 + y in
runOmega (liftA2 f (each xs) (each ys)) ===
runOmega (join (each (map (\x -> each (map (\y -> f x y) ys)) xs)))
, testProperty "liftA2 (,) undefined []" $ once $
runOmega (liftA2 (,) undefined (each [])) === ([] :: [((), ())])
, testProperty "liftA2 (,) (1 : undefined) (1 : undefined)" $ once $
take 1 (runOmega (liftA2 (,) (each (1 : undefined)) (each (1 : undefined)))) === [(1, 1)]
, adjustOption (min (mkTimeout 1000000)) $
testProperty "enumerate arithGrammar" $ once $
take 10 (runOmega (enumerate arithGrammar)) ===
["0","1","0+0","0*0","0+1","(0)","1+0","0*1","0+0*0","00"]
]
-- From https://web.archive.org/web/20140823135714/http://lukepalmer.wordpress.com/2008/05/02/enumerating-a-context-free-language/
data Symbol a
= Terminal a
| Nonterminal [[Symbol a]] -- a disjunction of juxtapositions
enumerate :: Symbol a -> Omega [a]
enumerate (Terminal a) = return [a]
enumerate (Nonterminal alts) = do
alt <- each alts -- for each alternative
rep <- mapM enumerate alt -- enumerate each symbol in the sequence
return $ concat rep -- and concatenate the results
arithGrammar :: Symbol Char
arithGrammar = s
where
s = Nonterminal [[add]]
add = Nonterminal [[mul], [add, Terminal '+', mul]]
mul = Nonterminal [[term], [mul, Terminal '*', term]]
term = Nonterminal [[number], [Terminal '(', s, Terminal ')']]
digit = Nonterminal $ map (map Terminal . show) [0..9]
number = Nonterminal [[digit], [digit, number]]