packages feed

spectacle-1.0.0: test/integration/Specifications/SimpleClock.hs

{-# LANGUAGE OverloadedLabels #-}

module Specifications.SimpleClock where

import Language.Spectacle
  ( Action,
    ActionType (ActionWF),
    Fairness (WeakFair),
    Modality (Always, Infinitely),
    Specification (Specification),
    Temporal,
    TemporalType (PropG, PropGF),
    interaction,
    modelcheck,
    plain,
    prime,
    specInit,
    specNext,
    specProp,
    (.=),
    pattern ConF,
    pattern NilF,
    type (#),
  )

-- ---------------------------------------------------------------------------------------------------------------------

interactClockSpec :: IO ()
interactClockSpec = interaction clockSpec

clockSpecCheck :: IO ()
clockSpecCheck = do
  modelcheck clockSpec >>= \case
    Left err -> print err
    Right xs -> print xs

-- ---------------------------------------------------------------------------------------------------------------------

type ClockSpec =
  Specification
    '["hour" # Int]
    '["next" # 'WeakFair]
    '["ticks" # 'Infinitely, "times" # 'Always]

clockNext :: Action '["hour" # Int] Bool
clockNext = do
  hour <- plain #hour
  if hour == 12
    then #hour .= pure 1
    else #hour .= pure (1 + hour)
  pure True

clockTicks :: Temporal '["hour" # Int] Bool
clockTicks = do
  hour <- plain #hour
  hour' <- prime #hour
  pure (1 + hour == hour')

clockTimes :: Temporal '["hour" # Int] Bool
clockTimes = do
  hour <- plain #hour
  pure (1 <= hour && hour <= 12)

clockSpec :: ClockSpec
clockSpec =
  Specification
    { specInit = ConF #hour (pure 1) NilF
    , specNext = ConF #next (ActionWF clockNext) NilF
    , specProp =
        ConF #ticks (PropGF clockTicks)
          . ConF #times (PropG clockTimes)
          $ NilF
    }