├── .gitignore ├── LICENSE ├── Main.hs ├── README.md ├── Setup.hs ├── machines-play.cabal └── stack.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | /dist/ 2 | .stack-work/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Alan Zimmerman 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Alan Zimmerman nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /Main.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeOperators #-} -- For :+: in signatures 2 | {-# LANGUAGE NoMonomorphismRestriction #-} 3 | {-# LANGUAGE FlexibleInstances #-} 4 | {-# LANGUAGE GADTs #-} 5 | 6 | import Data.Char 7 | import Data.Machine 8 | import qualified Data.Map as Map 9 | 10 | 11 | {- 12 | Simplest possible machine 13 | ------------------------- 14 | 15 | To do something useful, you need to call run, 16 | 17 | run :: MachineT Identity k b -> [b] 18 | 19 | The constructor for a MachineT is 20 | 21 | MachineT runMachineT :: m (Step k o (MachineT m k o)) 22 | 23 | In this simplest case m is Identity, so 24 | 25 | MachineT runMachineT :: Identity (Step k o (MachineT Identity k o)) 26 | 27 | The `Step k o r` functor is the base functor for a Machine or 28 | MachineT, and is normally generated via a `Plan`. 29 | 30 | 31 | This wants a Machine generating b, and will result in a list of b, 32 | with monadic effect 33 | 34 | A Machine gets built from a Plan. A Plan can be considered to be built 35 | up from one of the following primitives 36 | 37 | data Plan k o a 38 | = Done a 39 | | Yield o (Plan k o a) 40 | | forall z. Await (z -> Plan k o a) (k z) (Plan k o a) 41 | | Fail 42 | 43 | This Plan is a specification for a pure Machine, that reads inputs 44 | selected by k with types based on i, writes values of type o, and has 45 | intermediate results of type a. (What is `i`?) 46 | 47 | 48 | The simplest possible plan is simply 49 | 50 | yield b 51 | 52 | -} 53 | 54 | plana :: PlanT k Char m () 55 | plana = yield 'a' 56 | 57 | {- 58 | We make a Machine from the Plan. The type context must be properly 59 | defined or the construction will fail 60 | 61 | construct :: Monad m => PlanT k o m a -> MachineT m k o 62 | 63 | -} 64 | 65 | machinea :: Monad m => MachineT m k Char 66 | machinea = construct plana 67 | 68 | -- |simplest machine, using Identity Monad for pure results 69 | simplest :: [Char] 70 | simplest = run machinea 71 | 72 | {- 73 | *Main> simplest 74 | "a" 75 | *Main> 76 | 77 | Slightly more complex one, repeated data 78 | ---------------------------------------- 79 | 80 | type Source b = Monad m => MachineT m k b 81 | 82 | -} 83 | schar :: Source Char 84 | schar = source "abcde" 85 | {- 86 | Note: 87 | *Main> :t schar 88 | schar :: Monad m => MachineT m k Char 89 | 90 | *Main> run schar 91 | "abcde" 92 | 93 | A process that does not let the character b through 94 | -} 95 | nob :: Process Char Char 96 | nob = filtered (/='b') 97 | {- 98 | *Main> :t schar ~> nob 99 | schar ~> nob :: Monad m => MachineT m k Char 100 | *Main> run $ schar ~> nob 101 | "acde" 102 | *Main> 103 | 104 | 105 | 106 | Terminology (hand waving) 107 | 108 | Plan : is used to compose Machines 109 | 110 | Machine : is run to generate useful output. Generalisation of Source 111 | and Process 112 | 113 | Source : Machine generating output only. Effectively anchors one 114 | side of the processing chain with input 115 | 116 | Process : Machine that takes input of one type, transforms it, and 117 | generates output of a possible different type 118 | 119 | Automaton : for later investigation 120 | 121 | More pieces 122 | ----------- 123 | 124 | cap attaches a process to a source, generating a new source 125 | 126 | *Main> :t cap 127 | cap :: Monad m => Process a b -> Source a -> MachineT m k b 128 | *Main> :t cap nob schar 129 | cap nob schar :: Monad m => MachineT m k Char 130 | *Main> run $ cap nob schar 131 | "acde" 132 | *Main> 133 | 134 | 135 | How do we make a plan? 136 | ---------------------- 137 | 138 | From the slides 139 | 140 | stop :: Plan k o a 141 | 142 | The next primitives are used to sequence processing inside the 143 | Machine generated from the plan 144 | 145 | Generate output 146 | yield :: o -> Plan k o () 147 | 148 | Wait for input 149 | 150 | await :: Category k => Plan (k i) o i 151 | So k must have identity and composition 152 | 153 | awaits :: k i -> Plan k o i 154 | Think of it as 'await specific' 155 | 156 | 157 | Converting a plan into a Machine 158 | -------------------------------- 159 | 160 | construct :: Monad m => PlanT k o m a -> MachineT m k o 161 | Compile a machine to a model. 162 | 163 | repeatedly :: Monad m => PlanT k o m a -> MachineT m k o 164 | Generates a model that runs a machine until it stops, then start it up 165 | again. 166 | 167 | before :: Monad m => MachineT m k o -> PlanT k o m a -> MachineT m k o 168 | Evaluate a machine until it stops, and then yield answers according to the 169 | supplied model. 170 | 171 | Also to connect different machines 172 | 173 | fit :: Monad m => (forall a. k a -> k' a) -> MachineT m k o -> MachineT m k' o 174 | connect different kinds of machines, swapping one k function for another 175 | 176 | fitM :: (Monad m, Monad m') => (forall a. m a -> m' a) -> MachineT m k o -> MachineT m' k o 177 | connect different kinds of machines, swapping one monad for another 178 | 179 | pass :: k o -> Machine k o 180 | Given a handle, ignore all other inputs and just stream input 181 | from that handle 182 | 183 | The k functions define the sources, and how they are connected. 184 | There are two types, a Tee and a Wye. 185 | 186 | What is a Tee? 187 | ------------- 188 | 189 | A 'Machine' that can read from two input stream in a deterministic 190 | manner. 191 | 192 | type Tee a b c = Machine (T a b) c 193 | type TeeT m a b c = MachineT m (T a b) c 194 | Monadic version of Tee 195 | 196 | The `T` data type defines the input as follows 197 | 198 | data T a b c where 199 | Constructors 200 | L :: T a b a 201 | R :: T a b b 202 | 203 | This defines a type which can either have an L value or an R one, and 204 | takes a function (or Monad) generating the expected output type 'a' 205 | depending on which kind of input is presented. 206 | 207 | -} 208 | 209 | {- 210 | 211 | 212 | So lets try interleaving input from two sources 213 | -} 214 | streama,streamb :: Machine m Char 215 | streama = source "abcde" 216 | streamb = source "vwxyz" 217 | 218 | {- 219 | :t tee streama streamb 220 | tee streama streamb :: Monad m => TeeT m Char Char c -> TeeT m a b c 221 | 222 | 223 | I think the following is defined to read from two streams of Char, and 224 | generate output of Char 225 | -} 226 | 227 | -- myInterleave :: Tee Char Char Char -> Machine (((->) Char) :+: ((->) Char)) Char 228 | myInterleave :: Monad m => TeeT m Char Char c -> TeeT m a b c 229 | myInterleave = tee streama streamb 230 | 231 | 232 | myTee :: Tee Char Char Char 233 | myTee = repeatedly $ do 234 | x <- awaits L 235 | yield x 236 | y <- awaits R 237 | yield y 238 | 239 | 240 | -- myInterleave' :: Machine ((a -> Char) :+: (b -> Char)) Char 241 | 242 | myInterleave' :: Monad m => TeeT m a b Char 243 | myInterleave' = tee streama streamb myTee 244 | 245 | {- 246 | 247 | *Main> run myInterleave' 248 | "avbwcxdyez" 249 | *Main> 250 | 251 | -} 252 | 253 | -- --------------------------------------------------------------------- 254 | 255 | {- 256 | 257 | Exploring the Wye 258 | ----------------- 259 | 260 | type Wye a b c = Machine (Y a b) c 261 | A Machine that can read from two input stream in a non-deterministic manner. 262 | 263 | type WyeT m a b c = MachineT m (Y a b) c 264 | A Machine that can read from two input stream in a non-deterministic manner 265 | with monadic side-effects. 266 | 267 | 268 | The input descriptor for a Wye or WyeT 269 | 270 | data Y a b c where 271 | Constructors 272 | X :: Y a b a 273 | Y :: Y a b b 274 | Z :: Y a b (Either a b) 275 | 276 | So effectively a Wye is a heterogenous Tee, in that the two sources 277 | can feed different data types in. This could probably be emulated by 278 | appropriate choice of data type in a Tee 279 | 280 | 281 | The `wye` function is used to precompose two processes onto a Wye 282 | wye : Monad m => 283 | ProcessT m a a' -> ProcessT m b b' -> WyeT m a' b' c -> WyeT m a b c 284 | 285 | -} 286 | 287 | 288 | streamn :: Machine m Int 289 | streamn = source [1,2,3,4,5] 290 | 291 | -- |round robin input from the Wye 292 | myWye :: (Monad m) => MachineT m (Y Char Int) String 293 | myWye = repeatedly $ do 294 | x <- awaits X 295 | yield [x] 296 | 297 | y <- awaits Y 298 | yield (show y) 299 | 300 | wm :: Monad m => WyeT m Char Int String 301 | wm = wye streama streamn myWye 302 | 303 | {- 304 | *Main> run wm 305 | ["a","1","b","2","c","3","d","4","e","5"] 306 | *Main> 307 | -} 308 | 309 | -- | left-biased input from the Y, as per the implementation of `wye` 310 | myWye2 :: (Monad m) => MachineT m (Y Char Int) String 311 | myWye2 = repeatedly $ do 312 | x <- awaits Z 313 | case x of 314 | Left c -> yield [c] 315 | Right i -> yield (show i) 316 | 317 | wm2 :: Monad m => WyeT m Char Int String 318 | wm2 = wye streama streamn myWye2 319 | 320 | {- 321 | Note: prioritises the one source over the other. This is a feature of 'wye' 322 | *Main> run wm2 323 | ["a","b","c","d","e","1","2","3","4","5"] 324 | *Main> 325 | -} 326 | 327 | 328 | main = putStrLn "done" 329 | 330 | 331 | {- 332 | 333 | Experimenting with state machines 334 | ---------------------------------- 335 | 336 | Moore Machine : output values are determined solely by its current state. 337 | 338 | data Moore a b 339 | Constructors 340 | Moore b (a -> Moore a b) 341 | 342 | 343 | Mealy Machine : output values are determined both by its current state and 344 | the current inputs. 345 | 346 | newtype Mealy a b 347 | Constructors 348 | Mealy runMealy :: a -> (b, Mealy a b) 349 | 350 | 351 | Construct a Moore machine from a state valuation and transition function 352 | 353 | unfoldMoore :: (s -> (b, a -> s)) -> s -> Moore a b 354 | 355 | In the following examples, we use @auto@ which comes from the 356 | @'Data.Machine.Process.Automaton'@ typeclass: 357 | 358 | @ 359 | auto :: k a b -> Process a b 360 | @ 361 | 362 | This means that we can take some routing function, @k a b@, and lift it 363 | into a process. You can think of this as a specific @'construct'@ for 364 | automatons. 365 | -} 366 | 367 | -- For this next section, let's have two states and construct a simple state 368 | -- machine the state flips every time there is a new input. We'll use this 369 | -- state machine for the first examples of Moore and Mealy machines. 370 | 371 | data M1State = M1A | M1B deriving (Eq,Show,Ord) 372 | 373 | 374 | -- Construct a simple Moore machine 375 | -- -------------------------------- 376 | 377 | -- We will arbitrarily choose a Char type for input 378 | 379 | -- |Transition function from state M1A 380 | m1TransitionFmA :: Char -> Moore Char M1State 381 | m1TransitionFmA _ = Moore M1B m1TransitionFmB 382 | 383 | -- |Transition function from state M1B 384 | m1TransitionFmB :: Char -> Moore Char M1State 385 | m1TransitionFmB _ = Moore M1A m1TransitionFmA 386 | 387 | -- |Starting state and transitions for the machine 388 | m1 :: Moore Char M1State 389 | m1 = Moore M1A m1TransitionFmA 390 | 391 | -- Turn the Moore state machine into a process. 392 | -- 393 | -- Recall the definition of a process: 394 | -- > type ProcessT m a b = MachineT m (Is a) b 395 | m1a :: Monad m => MachineT m (Is Char) M1State 396 | m1a = auto m1 397 | 398 | m1m :: Monad m => MachineT m k M1State 399 | m1m = (source "abcde") ~> m1a 400 | 401 | {- 402 | *Main> run m1m 403 | [M1A,M1B,M1A,M1B,M1A,M1B] 404 | *Main> 405 | -} 406 | 407 | {- 408 | 409 | Construct a simple Mealy machine 410 | -------------------------------- 411 | 412 | This will have two states, and every time there is an input it changes 413 | state, and outputs the char used to transition. 414 | 415 | data Moore a b 416 | Constructors 417 | Moore b (a -> Moore a b) 418 | 419 | newtype Mealy a b 420 | Constructors 421 | Mealy runMealy :: a -> (b, Mealy a b) 422 | 423 | -} 424 | 425 | m2TransitionFmA :: Char -> (M1State, Mealy Char M1State) 426 | m2TransitionFmA _ = (M1B,Mealy m2TransitionFmB) 427 | 428 | m2TransitionFmB :: Char -> (M1State, Mealy Char M1State) 429 | m2TransitionFmB _ = (M1A,Mealy m2TransitionFmA) 430 | 431 | m2 :: Mealy Char M1State 432 | m2 = Mealy m2TransitionFmA 433 | 434 | -- Turn the Mealy state machine into a process 435 | m2a :: Monad m => MachineT m (Is Char) M1State 436 | m2a = auto m2 437 | 438 | m2m :: Monad m => MachineT m k M1State 439 | m2m = (source "abcde") ~> m2a 440 | 441 | {- 442 | *Main> run m2m 443 | [M1B,M1A,M1B,M1A,M1B] 444 | *Main> 445 | -} 446 | 447 | -- How is this different from the Moore machine? 448 | 449 | -- Moore b (a -> Moore a b) 450 | -- Mealy (a -> (b, Mealy a b)) 451 | 452 | -- Moore gives a state, and a function mapping from input to next state 453 | -- Mealy gives a function mapping from input to next (state,transition) 454 | 455 | -- When they run we only see the state as output. 456 | 457 | {- 458 | Mealy and Moore machines can both be represented by a 6-tuple, ( S, S0, Σ, Λ, T, G ), consisting of the following: 459 | 460 | - a finite set of states ( S ) 461 | - a start state (also called initial state) S0 which is an element of (S) 462 | - a finite set called the input alphabet ( Σ ) 463 | - a finite set called the output alphabet ( Λ ) 464 | - a transition function (T : S × Σ → S) 465 | - for Moore machines, this is a mapping from a _single state_ and the input alphabet to the next state. 466 | - for Mealy machines, this is a mapping from a _pair of states_ and the input alphabet to the next state. 467 | - an output function (G : S → Λ) 468 | - for Moore machines, this maps each _state_ and an input symbol to the corresponding output symbol. 469 | - for Mealy machines, this maps each _pair of states_ and an input symbol to the corresponding output symbol. 470 | 471 | Sometimes it's simpler to read if you unify the transition and output functions into a single function (T : S × Σ → S × Λ) 472 | 473 | A Moore machine can be regarded as a restricted type of finite state transducer. 474 | 475 | -- FIXME: add a little more depth as to what a "restricted type" means and if a Mealy machine is one too 476 | 477 | -} 478 | 479 | {- 480 | 481 | Mealy XOR example from https://en.wikipedia.org/wiki/Mealy_machine 482 | [Note, seems to be an error in the diagram, two states labelled S1] 483 | 484 | S = { S0,S1,Si} 485 | S0 = Si 486 | Σ = {0,1} 487 | Λ = {0,1} 488 | T : S × Σ → S × Λ = 489 | Si 0 -> (S0,0) 490 | Si 1 -> (S1,0) 491 | 492 | S0 0 -> (S0,0) 493 | S0 1 -> (S1,1) 494 | 495 | S1 0 -> (S0,1) 496 | S1 1 -> (S1,0) 497 | 498 | -} 499 | 500 | 501 | data XIn = I0 | I1 deriving (Eq,Show,Ord) 502 | 503 | data XOut = O0 | O1 deriving (Eq,Show) 504 | 505 | data XState = S0 XOut | S1 XOut | Si XOut deriving (Eq,Show) 506 | 507 | 508 | m3Mealy :: XIn -> (XState, Mealy XIn XState) 509 | m3Mealy = m3TransitionFmSi 510 | 511 | m3TransitionFmSi :: XIn -> (XState, Mealy XIn XState) 512 | m3TransitionFmSi I0 = (S0 O0,Mealy m3TransitionFmS0) 513 | m3TransitionFmSi I1 = (S1 O0,Mealy m3TransitionFmS1) 514 | 515 | m3TransitionFmS0 :: XIn -> (XState, Mealy XIn XState) 516 | m3TransitionFmS0 I0 = (S0 O0,Mealy m3TransitionFmS0) 517 | m3TransitionFmS0 I1 = (S1 O1,Mealy m3TransitionFmS1) 518 | 519 | m3TransitionFmS1 :: XIn -> (XState, Mealy XIn XState) 520 | m3TransitionFmS1 I0 = (S0 O1,Mealy m3TransitionFmS0) 521 | m3TransitionFmS1 I1 = (S1 O0,Mealy m3TransitionFmS1) 522 | 523 | m3 :: Mealy XIn XState 524 | m3 = Mealy m3TransitionFmSi 525 | 526 | -- Turn the Mealy state machine into a process 527 | m3a :: Monad m => MachineT m (Is XIn) XState 528 | m3a = auto m3 529 | 530 | m3m :: Monad m => MachineT m k XState 531 | m3m = (source [I0,I0,I0,I1,I1,I1,I0,I0]) ~> m3a 532 | 533 | {- 534 | *Main> run m3m 535 | [S0 O0,S0 O0,S0 O0,S1 O1,S1 O0,S1 O0,S0 O1,S0 O0] 536 | *Main> 537 | -} 538 | 539 | -- --------------------------------------------------------------------- 540 | 541 | -- |Transition function from state M4A 542 | m4TransitionFmSi :: XIn -> Moore XIn XState 543 | m4TransitionFmSi I0 = Moore (S0 O0) m4TransitionFmS0 544 | m4TransitionFmSi I1 = Moore (S1 O0) m4TransitionFmS1 545 | 546 | m4TransitionFmS0 I0 = Moore (S0 O0) m4TransitionFmS0 547 | m4TransitionFmS0 I1 = Moore (S1 O1) m4TransitionFmS1 548 | 549 | m4TransitionFmS1 I0 = Moore (S0 O1) m4TransitionFmS0 550 | m4TransitionFmS1 I1 = Moore (S1 O0) m4TransitionFmS1 551 | 552 | 553 | -- |Starting state and transitions for the machine 554 | m4 :: Moore XIn XState 555 | m4 = Moore (Si O0) m4TransitionFmSi 556 | 557 | -- Turn the Moore state machine into a process 558 | m4a :: Monad m => MachineT m (Is XIn) XState 559 | m4a = auto m4 560 | 561 | m4m :: Monad m => MachineT m k XState 562 | m4m = (source [I0,I0,I0,I1,I1,I1,I0,I0]) ~> m4a 563 | 564 | {- 565 | *Main> run m4m 566 | [Si O0,S0 O0,S0 O0,S0 O0,S1 O1,S1 O0,S1 O0,S0 O1,S0 O0] 567 | *Main> 568 | -} 569 | 570 | {- 571 | [Si O0 572 | ,S0 O0 573 | ,S0 O0 574 | ,S0 O0 575 | ,S1 O1 576 | ,S1 O0 577 | ,S1 O0 578 | ,S0 O1 579 | ,S0 O0] 580 | -} 581 | 582 | -- Meally [Si O0,S0 O0,S0 O0,S0 O0,S1 O1,S1 O0,S1 O0,S0 O1,S0 O0] 583 | -- Moore [S0 O0,S0 O0,S0 O0,S1 O1,S1 O0,S1 O0,S0 O1,S0 O0] 584 | 585 | -- ----------------------------------------------- 586 | 587 | {- 588 | understanding unfoldMoore 589 | ------------------------- 590 | 591 | from https://hackage.haskell.org/package/machines-0.6.1/docs/src/Data-Machine-Moore.html 592 | the definition of unfoldMoore is: 593 | 594 | @ 595 | -- | Construct a Moore machine from a state valuation and transition function 596 | unfoldMoore :: (s -> (b, a -> s)) -> s -> Moore a b 597 | unfoldMoore f = go where 598 | go s = case f s of 599 | (b, g) -> Moore b (go . g) 600 | {-# INLINE unfoldMoore #-} 601 | @ 602 | 603 | Let's take a longer look at the type signature with some psuedo-haskell: 604 | 605 | @ 606 | unfoldMoore :: 607 | (s -> -- a transition function which takes a state to generate... 608 | (,) -- a combination of... 609 | b -- ...whatever lives in the current state (b) 610 | (a -> s) -- ...plus a function that takes seen input (a) and steps us to the next state 611 | ) 612 | -> s -- constructing a Moore requires an explicit state to kick things off 613 | -> Moore a b -- and finally, we get back what we want 614 | @ 615 | 616 | Redoing the first two state example, using XIn: 617 | -} 618 | 619 | 620 | m6Fm1A :: XIn -> M1State 621 | m6Fm1A _ = M1B 622 | 623 | m6Fm1B :: XIn -> M1State 624 | m6Fm1B _ = M1A 625 | 626 | fMoore :: M1State -> (M1State, XIn -> M1State) 627 | fMoore M1A = (M1A,m6Fm1A) 628 | fMoore M1B = (M1B,m6Fm1B) 629 | 630 | 631 | -- So here, we can see that we can lift a function with the 632 | -- shape of a Moore, into a Moore, if we have all the right 633 | -- pieces 634 | m6 :: Moore XIn M1State 635 | m6 = unfoldMoore fMoore M1A 636 | 637 | -- furthermoore ; D, as expected, this fits right back into our machines 638 | -- infrastructure. No plan nessecary. 639 | m6m :: Monad m => MachineT m k M1State 640 | m6m = (source [I0,I1,I1,I1,I0]) ~> auto m6 641 | 642 | {- 643 | *Main> run m6m 644 | [M1A,M1B,M1A,M1B,M1A,M1B] 645 | *Main> 646 | -} 647 | 648 | -- --------------------------------------------------------------------- 649 | 650 | -- newtype Mealy a b 651 | -- Constructors 652 | -- Mealy runMealy :: a -> (b, Mealy a b) 653 | 654 | -- unfoldMealy :: (s -> a -> (b, s)) -> s -> Mealy a b 655 | 656 | -- Here a is XIn, 657 | -- b is XState 658 | 659 | initial :: [s] 660 | initial = [] 661 | 662 | fMealy :: [s] -> XIn -> (XState,[s]) 663 | fMealy [] = error "empty list" 664 | -- fMealy (x:xs) 665 | 666 | 667 | m5 :: Mealy XIn XState 668 | m5 = unfoldMealy fMealy initial 669 | 670 | -- | A 'Mealy' machine modeled with explicit state. 671 | unfoldMealy1 :: (s -> a -> (b, s)) -> s -> Mealy a b 672 | unfoldMealy1 f = go where 673 | go s = Mealy $ \a -> case f s a of 674 | (b, t) -> (b, go t) 675 | {-# INLINE unfoldMealy1 #-} 676 | 677 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | machines-play 2 | ============= 3 | 4 | Playing with https://github.com/ekmett/machines 5 | 6 | This version has been updated for machines 0.6.2, with stack LTS-8.21 7 | 8 | This is an experiment with machines, intending to show working 9 | examples of the various constructs. 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /machines-play.cabal: -------------------------------------------------------------------------------- 1 | name: machines-play 2 | version: 0.1.0.0 3 | synopsis: Playing with Haskell Machines 4 | -- description: 5 | homepage: https://github.com/alanz/machines-play 6 | license: BSD3 7 | license-file: LICENSE 8 | author: Alan Zimmerman 9 | maintainer: alan.zimm@gmail.com 10 | -- copyright: 11 | category: Control 12 | build-type: Simple 13 | cabal-version: >=1.8 14 | 15 | executable machines-play 16 | main-is: Main.hs 17 | -- other-modules: 18 | build-depends: base >= 4.7 && < 5 19 | , machines <= 0.6.2 20 | , transformers <= 0.5.2.0 21 | , containers <= 0.5.7.1 22 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by 'stack init' 2 | # 3 | # Some commonly used options have been documented as comments in this file. 4 | # For advanced use and comprehensive documentation of the format, please see: 5 | # http://docs.haskellstack.org/en/stable/yaml_configuration/ 6 | 7 | # Resolver to choose a 'specific' stackage snapshot or a compiler version. 8 | # A snapshot resolver dictates the compiler version and the set of packages 9 | # to be used for project dependencies. For example: 10 | # 11 | # resolver: lts-3.5 12 | # resolver: nightly-2015-09-21 13 | # resolver: ghc-7.10.2 14 | # resolver: ghcjs-0.1.0_ghc-7.10.2 15 | # resolver: 16 | # name: custom-snapshot 17 | # location: "./custom-snapshot.yaml" 18 | resolver: lts-8.21 19 | 20 | # User packages to be built. 21 | # Various formats can be used as shown in the example below. 22 | # 23 | # packages: 24 | # - some-directory 25 | # - https://example.com/foo/bar/baz-0.0.2.tar.gz 26 | # - location: 27 | # git: https://github.com/commercialhaskell/stack.git 28 | # commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a 29 | # - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a 30 | # extra-dep: true 31 | # subdirs: 32 | # - auto-update 33 | # - wai 34 | # 35 | # A package marked 'extra-dep: true' will only be built if demanded by a 36 | # non-dependency (i.e. a user package), and its test suites and benchmarks 37 | # will not be run. This is useful for tweaking upstream packages. 38 | packages: 39 | - '.' 40 | # Dependency packages to be pulled from upstream that are not in the resolver 41 | # (e.g., acme-missiles-0.3) 42 | extra-deps: [] 43 | 44 | # Override default flag values for local packages and extra-deps 45 | flags: {} 46 | 47 | # Extra package databases containing global packages 48 | extra-package-dbs: [] 49 | 50 | # Control whether we use the GHC we find on the path 51 | # system-ghc: true 52 | # 53 | # Require a specific version of stack, using version ranges 54 | # require-stack-version: -any # Default 55 | # require-stack-version: ">=1.4" 56 | # 57 | # Override the architecture used by stack, especially useful on Windows 58 | # arch: i386 59 | # arch: x86_64 60 | # 61 | # Extra directories used by stack for building 62 | # extra-include-dirs: [/path/to/dir] 63 | # extra-lib-dirs: [/path/to/dir] 64 | # 65 | # Allow a newer minor version of GHC than the snapshot specifies 66 | # compiler-check: newer-minor --------------------------------------------------------------------------------