blob: e54568785e2967ef5911f2a5238684d1cc8f50c3 (
plain) (
tree)
|
|
module sets
import StdBool
import StdEnum
from StdFunc import const, flip, o
import StdList
import StdOrdList
import StdOverloaded
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.List as L
from Data.List import instance Functor []
import qualified Data.Map as M
import Data.Maybe
from Text import <+
// It's been a long time since I worked with dynamics so I thought it would be
// nice to do that again.
:: SetState :== 'M'.Map Ident Dynamic
:: Ident :== String
// Like in the previous assignment: we can also use something like
// :: Sem a = Sem (SetState -> MaybeErrorString (a, SetState))
// and implement the monad functionality like that of StateT.
:: Sem a :== StateT SetState (MaybeError String) a
fail :: (String -> Sem a)
fail = StateT o const o Error
store :: Ident a -> Sem a | TC, toString a
store id x = modify ('M'.put id (dynamic x)) $> x
read :: Ident String -> Sem a | TC, toString a
read id type = gets ('M'.get id) >>= \v -> case v of
Just (v :: a^) -> pure v
Just d -> fail $ "Expected " <+ type <+ " for '" <+ id <+ "'; got " <+ typeCodeOfDynamic d
Nothing -> fail $ "Unknown variable '" <+ id <+ "'"
:: Element :== Sem Int
:: Set :== Sem [Int]
:: Logical :== Sem Bool
// -- Integer expressions --
integer :: (Int -> Element)
integer = pure
set :: ([Int] -> Set)
set = pure
size :: (Set -> Element)
size = fmap length
instance + Element where + a b = liftA2 (+) a b
instance - Element where - a b = liftA2 (-) a b
instance * Element where * a b = liftA2 (*) a b
instance + Set where + a b = liftA2 'L'.union a b
instance - Set where - a b = liftA2 'L'.difference a b
instance * Set where * a b = liftA2 'L'.intersect a b
(+:) infixl 6 :: (Element Set -> Set); (+:) = (+) o fmap pure
(:+) infixl 6 :: (Set Element -> Set); (:+) = flip (+:)
(:-) infixl 6 :: (Set Element -> Set); (:-) = flip $ flip (-) o fmap pure
(*:) infixl 6 :: (Element Set -> Set); (*:) = liftA2 $ map o (*)
eval :: ((Sem a) -> MaybeError String a)
eval = flip evalStateT 'M'.newMap
// -- Set expressions --
class variable a :: (String -> a)
instance variable Element where variable = flip read "Int"
instance variable Set where variable = flip read "[Int]"
// Convenience
intvar :: (String -> Element); intvar = variable
setvar :: (String -> Set); setvar = variable
class (=.) infix 2 a :: (Ident a -> a)
instance =. Element where =. = (=<<) o store
instance =. Set where =. = (=<<) o store
// -- Logical expressions --
true :: Logical
true = pure True
false :: Logical
false = pure False
(In) infix :: (Element Set -> Logical)
(In) = liftA2 isMember
class (==.) infix 4 a :: (a a -> Logical)
instance ==. Element where ==. = liftA2 (==)
instance ==. Set where ==. = liftA2 ((==) `on` sort)
class (<=.) infix 4 a :: (a a -> Logical)
instance <=. Element where <=. = liftA2 (<=)
instance <=. Set where <=. = liftA2 (flip (all o flip isMember))
Not :: (Logical -> Logical)
Not = fmap not
(||.) infixr 2 :: (Logical Logical -> Logical)
(||.) = liftA2 (||)
(&&.) infixr 3 :: (Logical Logical -> Logical)
(&&.) = liftA2 (&&)
// -- Statements --
// The Expression and Logical from last week are not needed; we can just use
// Sem Int, Sem [Int] and Sem Bool in the same pipeline.
If :: Logical (Sem a) (Sem a) -> Sem a
If b t e = b >>= \b -> if b t e
class for a :: Ident a Element -> Set
instance for Set where for k xs body = xs >>= mapM (flip (>>|) body o store k)
instance for Element where for k n body = n >>= \n -> for k (set [0..n-1]) body
(:.) infixl 1
(:.) :== (>>|)
Start =
( "\n", eval $ for "x" (set [0,1,2,3,4]) (variable "x" * integer 5)
, "\n", eval $ "y" =. integer 5 :. for "x" (intvar "y") (variable "x" * integer 5)
, "\n", eval $ factorial 5
, "\n")
factorial :: Int -> Element
factorial n =
"k" =. integer n :.
"r" =. integer 1 :.
for "x" (intvar "k")
(If (variable "x" ==. integer 0)
(variable "r") // for type-checking
("r" =. variable "r" * variable "x")) :.
variable "r"
|