Copyright | (c) Levent Erkok |
---|---|
License | BSD3 |
Maintainer | erkokl@gmail.com |
Stability | experimental |
Safe Haskell | None |
Language | Haskell2010 |
A transcription of Anthony Cowley's MicroController example, using the SBV plugin. For the original, see: http://acowley.github.io/NYHUG/FunctionalRoboticist.pdf
Parameters
The range detector must output if the range is larger than this amount.
The range detector must have sent an output before this many cycles have past.
The specification
checkSpec :: (Int -> Bool -> Int -> Int) -> Int -> Bool -> Int -> Bool Source
Given a last-signal-time calculator, named calculate
, check that it satisfies the following
three requirements: We must've just sent a signal if:
- minRate: The last-time we sent is strictly less than the
maxTimeSince
amount - minRange: We must've just sent a signal if the range is beyond
safetyDistance
- manualOverride: We must've just sent a signal if the manual-override is specified
A bad implementation
computeLastBad :: Int -> Bool -> Int -> Int Source
A "bad" implementation, see if you can spot the problem with it, before looking at the failed theorem below!
checkBad :: Int -> Bool -> Int -> Bool Source
Using SBV, prove that the computeLastBad
is indeed a bad implementation. Here's the output
we get from the plugin:
[SBV] MicroController.hs:85:1-8 Proving "checkBad", using Z3. [Z3] Falsifiable. Counter-example: range = 200 :: Int64 manual = False :: Bool timeSince = 9 :: Int64
We're being told that if the range is 200, and manual override is off, and time-since last is 9,
then our "calculator" returns 10. But that violates the minRate
requirement, since we
never want to go maxTimeSince
cycles without sending a signal!
A correct implementation
computeLastGood :: Int -> Bool -> Int -> Int Source
A "good" implementation, properly handling the off-by-one error of the original.
checkGood :: Int -> Bool -> Int -> Bool Source
We now verify that the good variant is indeed good. We have:
[SBV] MicroController.hs:108:1-9 Proving "checkGood", using Z3. [Z3] Q.E.D.
Exercise for the reader
It is easy to see that an implementation that always returns 0
(i.e., one that always
sends a signal) will also pass our specification!
- First, use the plugin to prove that such an implementation is indeed accepted.
- Then, modify the spec so that we require the
timeSince
parameter to actually get incremented under the correct conditions. - Show that your new spec outlaws the always
0
producing implementation.