module Door public export data Usage = Once | Many public export data Lin : (Type -> Type) -> Usage -> Type -> Type where Pure : (1 x : a) -> Lin m u a Lift : (1 x : m a) -> Lin m Many a BindOnce : (1 act : Lin m Once a) -> (1 k : (1 x : a) -> Lin m t b) -> Lin m t b BindMany : (1 act : Lin m Many a) -> (1 k : (x : a) -> Lin m t b) -> Lin m t b public export data Unrestricted : Type -> Type where MkUn : (x : a) -> Unrestricted a export pure : (1 x : a) -> Lin m u a pure = Pure export lift : (1 x : m a) -> Lin m Many a lift = Lift public export contType : (Type -> Type) -> Usage -> Usage -> Type -> Type -> Type contType m Once q a b = (1 x : a) -> Lin m q b contType m Many q a b = (x : a) -> Lin m q b public export (>>=) : {p : _} -> (1 f : Lin m p a) -> (1 k : contType m p q a b) -> Lin m q b (>>=) {p=Once} = BindOnce (>>=) {p=Many} = BindMany export run : Monad m => Lin m u t -> m t run (Pure x) = pure x run (Lift p) = p run (BindOnce act k) = do act' <- run act run (k act') run (BindMany act k) = do act' <- run act run (k act') public export One : (Type -> Type) -> Type -> Type One m = Lin m Once public export Any : (Type -> Type) -> Type -> Type Any m = Lin m Many data DoorState = Closed | Open -- changes start here openWhen : Bool -> DoorState openWhen ok = if ok then Open else Closed data Door : DoorState -> Type where MkDoor : (isOpen : Bool) -> Door (if isOpen then Open else Closed) -- Testing that 'if' works okay in an interface interface Doored (m : Type -> Type) where newDoor : One m (Door Closed) knock : (1 d : Door t) -> One m (Door t) openDoor : (1 d : Door Closed) -> One m (Res Bool (\ok => Door (if ok then Open else Closed))) closeDoor : (1 d : Door Open) -> One m (Door Closed) deleteDoor : (1 d : Door Closed) -> Any m ()