1- {-# LANGUAGE BangPatterns #-}
21{-# LANGUAGE ConstraintKinds #-}
32{-# LANGUAGE DataKinds #-}
3+ {-# LANGUAGE DerivingVia #-}
44{-# LANGUAGE EmptyCase #-}
55{-# LANGUAGE FlexibleContexts #-}
66{-# LANGUAGE FlexibleInstances #-}
77{-# LANGUAGE GADTs #-}
88{-# LANGUAGE MultiParamTypeClasses #-}
9+ {-# LANGUAGE PatternSynonyms #-}
910{-# LANGUAGE PolyKinds #-}
1011{-# LANGUAGE QuantifiedConstraints #-}
1112{-# LANGUAGE RankNTypes #-}
1213{-# LANGUAGE ScopedTypeVariables #-}
1314{-# LANGUAGE StandaloneDeriving #-}
1415{-# LANGUAGE StandaloneKindSignatures #-}
15- {-# LANGUAGE TypeFamilies #-}
1616{-# LANGUAGE TypeFamilyDependencies #-}
1717{-# LANGUAGE TypeOperators #-}
1818-- need for 'Show' instance of 'ProtocolState'
1919{-# LANGUAGE UndecidableInstances #-}
20+ {-# LANGUAGE ViewPatterns #-}
2021
2122-- | This module defines the core of the typed protocol framework.
2223--
@@ -43,6 +44,9 @@ module Network.TypedProtocol.Core
4344 , IsPipelined (.. )
4445 , Outstanding
4546 , N (.. )
47+ , Nat (Succ , Zero )
48+ , natToInt
49+ , unsafeIntToNat
4650 , ActiveAgency
4751 , ActiveAgency' (.. )
4852 , IsActiveState (.. )
@@ -51,6 +55,7 @@ module Network.TypedProtocol.Core
5155 ) where
5256
5357import Data.Kind (Constraint , Type )
58+ import Unsafe.Coerce (unsafeCoerce )
5459
5560import Data.Singletons
5661
@@ -504,3 +509,37 @@ type Outstanding :: IsPipelined -> N
504509type family Outstanding pl where
505510 Outstanding 'NonPipelined = Z
506511 Outstanding ('Pipelined n _ ) = n
512+
513+ -- | A value level inductive natural number, indexed by the corresponding type
514+ -- level natural number 'N'.
515+ --
516+ -- This is often needed when writing pipelined peers to be able to count the
517+ -- number of outstanding pipelined yields, and show to the type checker that
518+ -- 'SenderCollect' and 'SenderDone' are being used correctly.
519+ --
520+ newtype Nat (n :: N ) = UnsafeInt Int
521+ deriving Show via Int
522+
523+ data IsNat (n :: N ) where
524+ IsZero :: IsNat Z
525+ IsSucc :: Nat n -> IsNat (S n )
526+
527+ toIsNat :: Nat n -> IsNat n
528+ toIsNat (UnsafeInt 0 ) = unsafeCoerce IsZero
529+ toIsNat (UnsafeInt n) = unsafeCoerce (IsSucc (UnsafeInt (pred n)))
530+
531+ pattern Zero :: () => Z ~ n => Nat n
532+ pattern Zero <- (toIsNat -> IsZero ) where
533+ Zero = UnsafeInt 0
534+
535+ pattern Succ :: () => (m ~ S n ) => Nat n -> Nat m
536+ pattern Succ n <- (toIsNat -> IsSucc n) where
537+ Succ (UnsafeInt n) = UnsafeInt (succ n)
538+
539+ {-# COMPLETE Zero, Succ #-}
540+
541+ natToInt :: Nat n -> Int
542+ natToInt (UnsafeInt n) = n
543+
544+ unsafeIntToNat :: Int -> Nat n
545+ unsafeIntToNat = UnsafeInt
0 commit comments