1
+ {-# LANGUAGE LambdaCase #-}
2
+ {-# LANGUAGE MultiParamTypeClasses #-}
3
+ {-# LANGUAGE FlexibleInstances #-}
4
+ {-# LANGUAGE ScopedTypeVariables #-}
5
+
6
+ module REPL.Relations where
7
+
8
+ import Prelude hiding ((+) , (-) , (*) )
9
+ import Data.Functor (($>) )
10
+ import Control.Applicative ((<|>) )
11
+ import Text.Read (readMaybe )
12
+ import Control.Monad (join )
13
+ import Data.Tree (Tree (Node ))
14
+ import qualified Data.Set as S
15
+ import qualified Data.Map as M
16
+ import qualified Text.ParserCombinators.ReadP as P
17
+ import Text.ParserCombinators.ReadP (ReadP )
18
+ import System.Console.Haskeline (runInputT , defaultSettings , InputT , getInputLine , outputStrLn )
19
+ import Control.Exception.Base (Exception , catch , evaluate , throw )
20
+ import Control.Monad.IO.Class (liftIO )
21
+ import Autotool.Readable (Readable (.. ), spacedString , spaced , openPar , closePar )
22
+ import Autotool.DAO (toValue )
23
+ import qualified Autotool.DAO.Set as DAO
24
+ import qualified Autotool.DAO.Identifier as DAO
25
+ import qualified Autotool.DAO.Binding as DAO
26
+ import Autotool.Data.RelOp ((+) , (-) , (&) , (*) , inverse , transitiveClosure , reflexiveClosure , RelOpContext (.. ))
27
+ import Autotool.Data.LazyTree (mkOp0C , Op , showTree , evalTree' )
28
+ import Repl (Repl (.. ))
29
+
30
+ repl :: Repl
31
+ repl = Repl
32
+ { name = " rels"
33
+ , description = " Evaluate expressions on relations"
34
+ , loop = replFn
35
+ }
36
+
37
+ type Relation a = S. Set (a ,a )
38
+
39
+ data Context a = Context { _universe :: [a ], variables :: M. Map Char (Relation a ) }
40
+
41
+ newtype ReplException = UndefinedVar Char deriving (Show )
42
+
43
+ instance Exception ReplException
44
+
45
+ getVariable c k = case M. lookup k (variables c) of
46
+ Just v -> v
47
+ Nothing -> throw $ UndefinedVar k
48
+
49
+ addVariable :: Char -> Relation a -> Context a -> Context a
50
+ addVariable k v (Context uni vars) = Context uni (M. insert k v vars)
51
+
52
+ setUniverse :: [a ] -> Context a -> Context a
53
+ setUniverse u (Context _ vars) = Context u vars
54
+
55
+ instance (RelOpContext a ) (Context a ) where
56
+ universe (Context u _) = u
57
+
58
+ data Term a = B (DAO. Binding (Relation a )) | U [a ] | T (Tree (Op (Context a ) (Relation a )))
59
+
60
+ instance (Show a ) => Show (Term a ) where
61
+ show (B b) = show b
62
+ show (T t) = showTree t
63
+
64
+ instance {-# OVERLAPS #-} (Ord a , Readable a ) => Read (Term a ) where
65
+ readsPrec _ = P. readP_to_S readP
66
+
67
+ instance (Ord a , Readable a ) => Readable (Term a ) where
68
+ readP =
69
+ T <$> expr0
70
+ <|> B . fmap toValue <$> (readP :: ReadP (DAO. Binding (DAO. Set (a ,a ))))
71
+ <|> U <$> (spacedString " universe" *> readP)
72
+ where
73
+ expr0 = P. chainl1 expr1 (spacedString " &" $> node2 (&) )
74
+ expr1 = P. chainl1 expr2 (spacedString " +" $> node2 (+) )
75
+ expr2 = P. chainl1 expr3 (spacedString " -" $> node2 (-) )
76
+ expr3 = P. chainl1 term (spacedString " ." $> node2 (*) )
77
+ term =
78
+ variable
79
+ <|> node1 inverse <$> (spacedString " inverse" *> (variable <|> (openPar *> expr0 <* closePar)))
80
+ <|> node1 transitiveClosure <$> (spacedString " transitive_cl" *> (variable <|> (openPar *> expr0 <* closePar)))
81
+ <|> node1 reflexiveClosure <$> (spacedString " reflexive_cl" *> (variable <|> (openPar *> expr0 <* closePar)))
82
+ variable = node0 . var <$> spaced (P. satisfy (`elem` [' A' .. ' Z' ]))
83
+ var name = mkOp0C [name] (`getVariable` name)
84
+ node0 op = Node op []
85
+ node1 op a = Node op [a]
86
+ node2 op a b = Node op [a,b]
87
+
88
+ replFn :: IO ()
89
+ replFn = runInputT defaultSettings (help >> loop (Context [] M. empty))
90
+ where
91
+ help = outputStrLn $ unlines
92
+ [ " HELP"
93
+ , " Define new sets relations: S = {(1,2), (3,4)}"
94
+ , " Define universe: universe [1,2,3,4]"
95
+ , " Evaluate Expressions like: (S + R) . (S - R)"
96
+ , " "
97
+ , " Available operators:"
98
+ , " - &"
99
+ , " - +"
100
+ , " - -"
101
+ , " - ."
102
+ , " - inverse (needs defined universe)"
103
+ , " - transitive_cl"
104
+ , " - reflexive_cl"
105
+ ]
106
+ loop :: Context Int -> InputT IO ()
107
+ loop c = do
108
+ line <- getInputLine " relations > "
109
+ let term = readMaybe <$> line
110
+ case join term of
111
+ Nothing -> loop c
112
+ (Just (B b)) -> let (k,v) = DAO. toPair b in loop (addVariable (DAO. fromId k) v c)
113
+ (Just (U u)) -> loop (setUniverse u c)
114
+ (Just (T t)) -> liftIO (eval c t)
115
+ >>= \ case
116
+ (Right val) -> return $ show (toValue val :: DAO. Set (Int ,Int ))
117
+ (Left err) -> return err
118
+ >>= outputStrLn
119
+ >> loop c
120
+ eval c t = catch (Right <$> evaluate (evalTree' c t)) onError
121
+ onError (UndefinedVar k) = return $ Left $ " Error: Undefined variable " ++ show k
0 commit comments