summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assignment-9/sets.icl149
1 files changed, 149 insertions, 0 deletions
diff --git a/assignment-9/sets.icl b/assignment-9/sets.icl
new file mode 100644
index 0000000..e545687
--- /dev/null
+++ b/assignment-9/sets.icl
@@ -0,0 +1,149 @@
+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"