module sets
// Laurens Kuijper, s4467299
// Camil Staps, s4498062
import StdArray
import StdBool
import StdEnum
from StdFunc import flip, id, o
import StdGeneric
import StdInt
import StdList
import StdString
import Control.Applicative
import Control.Monad
import Control.Monad.State
import Data.Error
from Data.Func import $, on, `on`
import Data.Functor
import qualified Data.Map as M
import Data.List
import Data.Maybe
from Text import <+, class Text(concat), instance Text String
instance + [a] | Eq a where + xs ys = xs - ys ++ ys
instance - [a] | Eq a where - xs ys = removeMembers xs ys
instance * [a] | Eq a where * xs ys = [x \\ x <- xs | hasElem x ys]
addElem :: a [a] -> [a] | Eq a
addElem x xs = if (isMember x xs) xs [x:xs]
removeElem :: (a [a] -> [a]) | Eq a
removeElem = removeMember
hasElem :: (a [a] -> Bool) | Eq a
hasElem = isMember
/**
* This Expression type is agnostic with regards to the expression type, so it
* can handle sets of booleans, sets of sets, reals, etc. Because of this, we
* only need Elem and not New and TRUE/FALSE.
*/
:: Expression a
= Elem a
| Variable Ident
| E.b: Size (Bimap a Int) (Set b) & TC, Print b
| (+.) infixl 6 (Expression a) (Expression a) & + a
| E.b: AddElemAndSet (Bimap a [b]) (Elem b) (Set b) & TC, Eq, Print b
| E.b: AddSetAndElem (Bimap a [b]) (Set b) (Elem b) & TC, Eq, Print b
| (-.) infixl 6 (Expression a) (Expression a) & - a
| E.b: RemoveFromSet (Bimap a [b]) (Set b) (Elem b) & TC, Eq, Print b
| (*.) infixl 7 (Expression a) (Expression a) & * a
| E.b: MulElemAndSet (Bimap a [b]) (Elem b) (Set b) & TC, *, Print b
| (=.) infixl 2 Ident (Expression a)
| Not (Bimap a Bool) (Elem Bool)
| Or (Bimap a Bool) (Elem Bool) (Elem Bool)
| And (Bimap a Bool) (Elem Bool) (Elem Bool)
| E.b: In (Bimap a Bool) (Elem b) (Set b) & TC, Eq, Print b
| E.b: Eq (Bimap a Bool) (Expression b) (Expression b) & TC, Eq, Print b
| E.b: Le (Bimap a Bool) (Expression b) (Expression b) & TC, Ord, Print b
| If (Elem Bool) (Expression a) (Expression a)
| E.b c: For (Bimap a [b]) Ident (Set c) (Expression b) & TC, Print b & TC, Print c
| E.b: (:.) infixl 1 (Expression b) (Expression a) & TC, Print b
// Convenience
elem :== Elem
var :== Variable
size :== Size bimapId
for :== For bimapId
(+:) infixl 6; (+:) :== AddSetAndElem bimapId
(:+) infixl 6; (:+) :== AddElemAndSet bimapId
(-:) infixl 6; (-:) :== RemoveFromSet bimapId
(:*) infixl 7; (:*) :== MulElemAndSet bimapId
(==.) infix 4; (==.) :== Eq bimapId
(<=.) infix 4; (<=.) :== Le bimapId
(||.) infixr 2; (||.) :== Or bimapId
(&&.) infixr 3; (&&.) :== And bimapId
:: SetState :== 'M'.Map Ident Dynamic
:: Sem a :== StateT SetState (MaybeError String) a
:: Set a :== Expression [a]
:: Elem a :== Expression a
:: Ident :== String
fail :: (String -> StateT s (MaybeError String) a)
fail = StateT o const o Error
store :: Ident v -> StateT SetState m v | Monad m & TC v
store i v = modify ('M'.put i (dynamic v)) $> v
read :: Ident -> StateT SetState (MaybeError String) v | TC v
read i = gets ('M'.get i) >>= \v -> case v of
Just (x :: v^) -> pure x
Just d -> fail $ "type error, " <+ typeCodeOfDynamic d <+ " for '" <+ i <+ "'"
Nothing -> fail $ "unknown variable '" <+ i <+ "'"
eval :: (Expression a) -> Sem a | TC a
eval (Elem x) = pure x
eval (Variable id) = read id
eval (Size bm s) = bm.map_from <$> length <$> eval s
eval (x +. y) = (liftA2 (+) `on` eval) x y
eval (AddElemAndSet bm e s) = bm.map_from <$> liftA2 addElem (eval e) (eval s)
eval (AddSetAndElem bm s e) = bm.map_from <$> liftA2 addElem (eval e) (eval s)
eval (x -. y) = (liftA2 (-) `on` eval) x y
eval (RemoveFromSet bm s e) = bm.map_from <$> liftA2 removeElem (eval e) (eval s)
eval (x *. y) = (liftA2 (*) `on` eval) x y
eval (MulElemAndSet bm e s) = bm.map_from <$> liftA2 (map o (*)) (eval e) (eval s)
eval (id =. e) = eval e >>= store id
eval (Not bm l) = bm.map_from <$> not <$> eval l
eval (Or bm x y) = bm.map_from <$> (liftA2 (||) `on` eval) x y
eval (And bm x y) = bm.map_from <$> (liftA2 (&&) `on` eval) x y
eval (In bm e s) = bm.map_from <$> liftA2 hasElem (eval e) (eval s)
eval (Eq bm x y) = bm.map_from <$> liftA2 (==) (eval x) (eval y)
eval (Le bm x y) = bm.map_from <$> liftA2 (<=) (eval x) (eval y)
eval (If b t e) = eval b >>= \b -> eval $ if b t e
eval (For bm id s e) = bm.map_from <$> (eval s >>= iterate e)
where
iterate :: (Elem b) -> [a] -> Sem [b] | TC a & TC b
iterate e = mapM (\x -> store id x >>| eval e)
eval (s :. t) = eval s >>| eval t
:: Print :== [String] -> [String]
class Print a where pr :: a -> Print
print :: (a -> String) | Print a
print = concat o flip pr []
between :: a b c -> Print | Print a & Print b & Print c
between a b c = pr b o pr a o pr c
surround :: a b c -> Print | Print a & Print b & Print c
surround a b c = pr a o pr c o pr b
parens :: (a -> Print) | Print a
parens = surround "(" ")"
braces :: (a -> Print) | Print a
braces = surround "{" "}"
interpr :: a [b] -> Print | Print a & Print b
interpr _ [] = id
interpr _ [x] = pr x
interpr g [x:xs] = between g x (interpr g xs)
instance Print String where pr s = (++) (pure s)
instance Print Char where pr c = pr {#c}
instance Print Int where pr i = pr (toString i)
instance Print Bool where pr b = pr (toString b)
instance Print [a] | Print a where pr xs = surround "[" "]" (interpr "," xs)
instance Print Print where pr p = p
instance Print (Expression a) | Print a
where
pr (Elem x) = pr x
pr (Variable x) = surround '"' '"' x
pr (Size _ xs) = surround "size (" ")" xs
pr (x +. y) = parens (between " +. " x y)
pr (AddElemAndSet _ e s) = parens (between " :+ " e s)
pr (AddSetAndElem _ s e) = parens (between " +: " s e)
pr (x -. y) = parens (between " -. " x y)
pr (RemoveFromSet _ s e) = parens (between " -: " s e)
pr (x *. y) = parens (between " *. " x y)
pr (MulElemAndSet _ e s) = parens (between " :* " e s)
pr (id =. e) = between " =. " id e
pr (Not _ l) = pr "~" o parens l
pr (Or _ x y) = parens (between " ||. " x y)
pr (And _ x y) = parens (between " &&. " x y)
pr (In _ e s) = parens (between " ∈ " e s)
pr (Eq _ x y) = parens (between " == " x y)
pr (Le _ x y) = parens (between " <= " x y)
pr (If b t e) = pr "if " o pr b o pr " " o braces t o pr " " o braces e
pr (For _ id s e) = pr "for " o between " ∈ " id s o pr " " o braces e
pr (s :. t) = between " :. " s t
/**
* We did not manage to get the iTasks simulator working, because the compiler
* 'cannot build a generic representation of an existential type'.
* We're sure it would be *possible* by implementing an Editor manually,
* forcing all Bimaps to bimapId and using cast :: a -> b in case of type
* errors, but did not try to do this due to time constraints.
*/
Start = (evalStateT (eval stmt) 'M'.newMap, print stmt)
where
stmt :: Expression [Int]
stmt =
"x" =. elem [3..10] :.
"y" =. elem 0 :.
elem 10 :* for "i" (elem [1..5] +. var "x") (
"y" =. var "y" +. elem 1 :.
var "i" *. var "y"
)