-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStateMachine.hs
More file actions
175 lines (117 loc) · 5.8 KB
/
StateMachine.hs
File metadata and controls
175 lines (117 loc) · 5.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
{-# LANGUAGE GADTs
, FlexibleInstances
, TypeFamilies
, FlexibleContexts
, DeriveFunctor
, MultiParamTypeClasses
#-}
module StateMachine where
import Control.Applicative
import Control.Arrow
import Data.Monoid
import Data.Function(on)
import Control.Category
import Prelude hiding ((.),id) -- we use those from Category...
import Internal.MachineComponent
import Data.Char
import Data.Time.Clock
import Data.Maybe
{- Author : Alejandro Durán Pallarés (That's me...)
-}
{-
Some of the implementations has been postpone till the InjectedMachine [See Internal]
is defined.
[This is still under construction :-) ]
-}
-- Represent an StateMachine in a set of concurrent states of execution.
-- it is feeded with value of type "input" and out values of type" output" when success.
data StateMachine input output where
Wrap:: (MachineCombinator stm, Input stm ~ input) => stm output -> StateMachine input output
instance Functor (StateMachine input) where
fmap f (Wrap stm)= Wrap$ fmap f stm
instance Applicative (StateMachine input) where
pure x = Wrap$Step True (Just x) (const Nothing)
Wrap stm1 <*> Wrap stm2
| Just f <- collect stm1 = Wrap$Sequenced stm2 (Left (stm1, f<$>stm2))
| otherwise = Wrap$Sequenced stm2 (Right(Left stm1))
instance Alternative (StateMachine input) where
empty = Wrap$Step True Nothing (const Nothing)
Wrap stm1 <|> Wrap stm2 = Wrap$Parallel(Left (stm1,stm2))
some (Wrap stm)
| Just x <- collect stm = Wrap$Loop stm ( ((.)(x:).(:)) <$> stm)
| otherwise = Wrap$Loop stm ( (:) <$> stm)
many v = some v <|> pure [] -- I'm wondering why I do need this...
-- TODO: check the laws!!
--instance Category StateMachine where
--instance Arrow StateMachine where
--instance ArrowChoice StateMachine where
--contraMap::(a->b) -> StateMachine b c -> StateMachine a c
--contraMap = undefined
with::(a -> Maybe b) -> StateMachine a b
with f = Wrap$Step True Nothing f
such::(a -> Bool) -> StateMachine a a
such cond = with (\x -> if cond x then Just x else Nothing)
element::(Eq a) => a -> StateMachine a a
element x = such (==x)
anything::StateMachine a a
anything = with return
separatedBy::StateMachine a c -> StateMachine a b -> StateMachine a [b]
separatedBy sep stm = (:) <$> stm <*> many (sep *> stm)
enclosed::StateMachine a b -> StateMachine a c -> StateMachine a d -> StateMachine a d
enclosed lft rght stm = lft *> stm <* rght
string::(Eq a) => [a] -> StateMachine a [a]
string stream = foldr (\a b -> (:) <$> a <*> b) (pure []) (map element stream)
parse::StateMachine a b -> [a] -> Maybe b
parse (Wrap stm) = (collect =<<) . foldr ((=<<).trigger) (Just stm).reverse
--tokenized::[StateMachine a b] -> [a] -> ([b],[a])
--tokenized = undefined
------------------------------------------------------------------------------------------------
---- TODO: this functions will rely on the Arrowed combinators not defined yet....
notBeing::StateMachine a b -> StateMachine a c -> StateMachine a b
notBeing = undefined
whateverBut:: StateMachine a b -> StateMachine a ()
whateverBut = undefined
being::StateMachine a b -> StateMachine a c -> StateMachine a (b,c)
being = undefined --
recording::StateMachine a b -> (a -> acc -> acc) -> StateMachine a (Maybe b,acc)
recording = undefined
recordingError::StateMachine a b -> (a -> err -> err) -> StateMachine (Either b err) b
recordingError = undefined
-- This function is supposse to behave somehow as Flex
stateFullTokenize::(state -> [StateMachine a (b,state)]) -> state -> ([b],[state],[a])
stateFullTokenize = undefined
parseText::StateMachine Char b -> String -> Either (Int,Int,String) b
parseText = undefined
--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------
-----TODO: add more instances...
--TODO, add Standards types, lists, int, bool ,etc...
------------- Useful
class DefinedStateMahine inn out where
field::StateMachine inn out
instance(DefinedStateMahine Char out)=> DefinedStateMahine Char (Maybe out) where
field = optional field
instance DefinedStateMahine Char Int where
field = foldl (\acc c-> (ord c - 48) + 10*acc) 0
<$> some (such isDigit)
--Might get this one out of here....is a bit pointless...
instance DefinedStateMahine Char () where
field = () <$ some (such isSpace)
--Time can be tedious for parsing...related instances can be quiet useful....
--
-- Okey, true, this one is just for the example...but once extended to a more general
-- format it could be used somewhere else....
instance DefinedStateMahine Char DiffTime where
field = format <$> digit <*> (digit <* element' ':')
<*> digit <*> (digit <* element' ':')
<*> digit <*> digit
<*> optional ((,,)<$> ((element' '.' <|> element' ',') *> digit) <*> digit <*> digit)
where
format a b c d e f p = let [h1, h0, m1, m0, s1, s0,p2,p1,p0 ] = fmap (\c->fromIntegral (ord c) - 48 )
[a, b, c, d, e, f, g, h,i]
(g,h,i) = fromMaybe ('0','0','0') p
in (secondsToDiffTime $ ((h1*10+h0)*60 + m1*10+m0)*60 + s1*10+s0)
+ (picosecondsToDiffTime $ (p2*100 + p1*10+p0)*(10^9))
digit = such isDigit
element' x = space *> element x <* space
space = many $ such isSpace