The AFSM package

[ Tags: frp, library, mit ] [ Propose Tags ]

Arrowized functional state machines. This module is inspired by Yampa and the paper Functional Reactive Programming, Continued* written by Henrik Nilsson, Antony Courtney and John Peterson.


[Skip to Readme]

Properties

Versions 0.1.0.0, 0.1.1.0, 0.1.1.1, 0.1.1.2, 0.1.1.3, 0.1.2.0, 0.1.3.0, 0.1.3.1 (info)
Change log CHANGELOG.md
Dependencies base (>=4.7 && <5) [details]
License MIT
Copyright Hanzhong Xu, Meng Meng
Author Hanzhong Xu, Meng Meng
Maintainer hanzh.xu@gmail.com
Category FRP
Home page https://github.com/PseudoPower/AFSM
Source repo head: git clone git@github.com:PseudoPower/AFSM.git
Uploaded Tue Apr 12 04:26:43 UTC 2016 by hanzhxu
Distributions NixOS:0.1.3.1
Downloads 1626 total (75 in the last 30 days)
Rating 2.0 (votes: 1) [estimated by rule of succession]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2016-11-26 [all 1 reports]
Hackage Matrix CI

Modules

[Index]

Downloads

Maintainer's Corner

For package maintainers and hackage trustees


Readme for AFSM-0.1.2.0

[back to package description]

Arrowized functional state machines

Introduction

The intuitive way to understand the state machine is that it have four parts, state, storage, input and output. Each state has its own transition function which takes the storage and the input, updates the storage and the state, and gives the output.

The abstract way is thinking the state machine as the stateful function.

Now, let us put these two ways together. Our plan is using the stateful function as the interface(making it to be an instance of the Arrow type class), but users can build state machines in an intuitive way.

Basic Concepts

The SM a b type denotes stateful functions from a to b. Also, It is an instance of the Arrow type class.

-- | 'SMState' is the type of transition functions
--     s: storage, a: input, b: output
type SMState s a b = (s -> a -> (SM a b, b))

-- | 'SM' is the type representing state machines.
data SM a b where
  SM :: (SMState s a b) -> s -> SM a b
--
--    a  /--------\  b
--  >--->| SM a b |>--->
--       \--------/
--
-- (>>>) :: SM a b -> SM b c -> SM a c
--
--    a  /--------\  b  /--------\  c
--  >--->| SM a b |>--->| SM b c |>--->
--       \--------/     \--------/
--
--
-- first :: SM a b -> SM (a, c) (b, c)
--
--    a  /--------------\  b
--  >--->|>-> SM a b >->|>--->
--       |              |
--  >--->|>------------>|>--->
--    c  \--------------/  c
--
-- (***) :: SM a b -> SM c d -> SM (a, c) (b, d)
--
--    a  /--------------\  b
--  >--->|>-> SM a b >->|>--->
--       |              |
--  >--->|>-> SM c d >->|>--->
--    c  \--------------/  d
--
-- (&&&) :: SM a b -> SM a c -> SM a (b, c)
--
--            /--------\  b
--       /--->| SM a b |>---\
--    a  |    \--------/    |  (b,c)
--  >--->|                  |>------->
--       |    /--------\  c |
--       \--->| SM a c |>---/
--            \--------/
--

-- execute SM a b with input [a].
exec :: SM a b -> [a] -> (SM a b, [b])

From a theoretical point of view, this model is a simplified version of FRP, but adding states on functions directly. In another word, it is switching the focus from time to states.

From an engnieering point of view, the other difference from AFRP(Yampa) is that we provide the constructor to use the transition function SMState s a b :: s -> a -> (SM a b, b) to build SM a b directly where s donates the storage type.

Simplifed model

In functional reactive programming(FRP), the key concepts are the signal, Signal a :: Time -> a, and the signal function from signal to signal, SF a b :: Signal a -> Signal b.

The model of FRP is beautiful, but one diffcult thing is that the signal is continuous function, and our computers are discrete systems.

However, what if we do not care about time, and only focus on the sequence of input. There is reason to believe that computational tasks usually are time-insensitive. For example, the parsing process. So [a] and [Event a] are the only things we expected in our system.

For discrete system, simplifying the input type is kind of generalizing [(Time,a)] to [a]. This simplifed model is still able to process the time sequences by using [(Time, a)] as the input. In conclusion, we doesn't consider time as an essential part of the input, but if the input involves time, users can add time back as a part of the input.

Stateful function(Storage)

Usually, the state can be abstracted to the summary of input history. With the ArrowLoop instance, we can create stateful functions in FPR. For example, if we want to get a function SF a b with state c. We first write a function SF (a, c) (b, c), then use loop :: SF (a, c) (b, c) -> SF a b to get the stateful function SF a b.

But I prefer to think the pure function as the stateful function with state (), because the stateful function gives us a more natural way to represent the control flow. Also, it give us the ability to switch the function itself based on different inputs.

Implementation

The key idea is using the GADTs extension to hide the state(storage) type. If we do not use the GADTs extension, then SM a b will become SM s a b where s denotes the state(storage) type.

Examples

Reverse Polish notation(RPN.hs)

It is also known as postfix notation, and it is very straightforward example. The input is the infix expression, and the output is the value. First, we build a SM named in2post to convert infix notation to postfix expression. Then we build a SM named post2ret to evaluate the valus. Finally, we use them to compose in2ret = in2post >>> post2ret.

To-Do

  • Basic state machines
  • Event
  • More high order functions
  • Another DSL to build transition functions?

References

Functional Reactive Programming, Continued

Yampa - Haskell Wiki

Haskell/Arrow tutorial

  • Just realize that both AFRP and our model are very similar with Circuit. Actually, FRP is simulating signal systems, also it's why I prefer to use the name signal function instead of behavior function. On the other hand, AFRP is AFSM with fix storage type DTime, and the benefit is that it does not require the GADTs extension.