requisite puts trust, confidence, and freshness requirements in Haskell
function signatures.
Add requisite ^>= 0.1.0 to build-depends in your Cabal file.
Use focused imports at application boundaries:
import Control.Exception (displayException)
import Requisite.Confidence (Certain, foldGate, gate, mkConfident)
import Requisite.Fresh (check, fetch, seconds, staleReason, staleValue)
import Requisite.Trust (Tainted, Trusted, fromInput, trySanitize)Requisite is a convenience re-export for examples and small programs. The
public library modules are marked Safe; applications need no language
extensions and the examples use Haskell 2010.
repositoryLookup :: Tainted Trusted Int -> IO Customer
raw = fromInput requestField
customerId = trySanitize parseCustomerId rawTainted has a hidden constructor. Trusted and Untrusted are uninhabited
type-level markers with no data constructors. Both Tainted parameters have
nominal roles, so Data.Coerce cannot forge the wrapper, change its trust
state, or change its wrapped representation.
mapUntrusted and untrustedValue support inspection and preprocessing without
promotion. sanitize and trySanitize are the only trusted transitions;
widen only lowers Trusted to Untrusted.
Sanitizer results are evaluated to weak head normal form at the transition. Deep structures remain lazy; force them inside the application policy when validation depends on complete evaluation.
scored <- either (fail . displayException) pure (mkConfident prediction 0.98)
foldGate
commit
review
record
(gate scored)Probabilities must be finite and in [0, 1]. Default likely and certain
thresholds are 0.60 and 0.95. mkThresholds may raise the certain boundary
but not lower it. Thresholds uses private positional fields plus explicit
accessors, so record update cannot bypass validation.
Gate constructors are private. gateTier inspects the public Tier, while
foldGate releases the payload through one of three handlers. Confident
intentionally has no payload accessor: confidence-sensitive values are released
by classification.
Tier ordering follows confidence:
UnsureTier < LikelyTier < CertainTier.
Only the certain handler receives Certain, whose constructor cannot be forged
with ordinary constructors or Data.Coerce. Haskell is not linear: a token can
be retained and reused after a qualifying gate. It proves that a qualifying
classification occurred, not that authorization is single-use. Guarantees also
exclude undefined, unsafeCoerce, and other explicit departures from type
safety.
quote <- fetch (seconds 30) price
result <- check quote
case result of
Right current -> charge current
Left expired -> do
audit (staleValue expired)
refresh (staleReason expired)Fresh has no unchecked payload accessor. check and checkAt return either a
current payload or a StaleValue; expired payload recovery is therefore
explicit and carries its Stale timing information.
The clock API has paired IO and pure forms:
fetchandcheckread the process monotonic clock.fetchAttrusts an injected fetch instant for deterministic code.fromFetchedAtvalidates a recorded fetch instant against the live clock.fromFetchedAtWithvalidates namedFetchTimingfields without IO.checkAtandremainingAtinject the read instant.
Durations and instant movement saturate on overflow. Values are meaningful only within one process. Whether suspend advances the monotonic clock is platform-dependent, so this API is unsuitable for persisted deadlines or wall-clock expiry.
Payloads are evaluated to weak head normal form before fetch reads the clock.
Deeper evaluation remains the caller's responsibility.
A branded withLive API is omitted. Its rank-2, runST-shaped encoding would
not make ordinary Haskell payloads affine or strengthen the runtime TTL check.
Error Show instances are structural. Use displayException for user-facing
messages. Payload wrappers such as Confident, Gate, Fresh, and
StaleValue deliberately lack Show instances to avoid accidental value
logging.
The default path is suitable for Hackage builders:
cabal build all -f-compile-fail -f-examples
cabal test requisite-test -f-compile-fail -f-examples
cabal check
cabal haddock allCompiler-diagnostic contracts and the example are manual flags:
REQUISITE_GHC="$(command -v ghc)" \
cabal test all -fcompile-fail -fexamples
cabal run -fexamples payment-flowCompile-fail tests select REQUISITE_GHC when set, otherwise the ghc on
PATH; CI sets it explicitly. Diagnostics are whitespace, quote, case, and
path-separator normalized. The source filename is verified, then removed before
message-specific phrases are checked. The harness also verifies that its case
directory exactly matches the manifest and mutation-tests its two former
filename false positives. Each case uses an exception-safe system temporary
directory.
cabal.project pins the Hackage index state. CI covers the tested GHC range on
Linux, macOS, and Windows, and enables both manual flags.
The package name is
requisite, and its source is
slepp/requisite-haskell.
Validate a release candidate before uploading because Hackage package versions
cannot be replaced. See RELEASING.md for the candidate-first
workflow.
Copyright 2026 Stephen Olesen.
Licensed under either Apache-2.0 or MIT, at your option.