From a44e09275baa762c2e7fba28bc2254c333539de4 Mon Sep 17 00:00:00 2001 From: harryprayiv Date: Fri, 13 Mar 2026 00:03:03 -0400 Subject: [PATCH 1/8] version bump for use in another project --- crem.cabal | 18 ++++++++++-------- flake.lock | 30 +++++++++++++++--------------- flake.nix | 2 +- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/crem.cabal b/crem.cabal index d7294f5..da8c783 100644 --- a/crem.cabal +++ b/crem.cabal @@ -1,6 +1,6 @@ cabal-version: 2.0 --- This file has been generated from package.yaml by hpack version 0.35.2. +-- This file has been generated from package.yaml by hpack version 0.38.3. -- -- see: https://github.com/sol/hpack @@ -22,6 +22,8 @@ tested-with: , GHC ==9.2.7 , GHC ==9.4.4 , GHC ==9.6.1 + , GHC ==9.8.4 + , GHC ==9.10.1 extra-source-files: README.md CHANGELOG.md @@ -54,11 +56,11 @@ library PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.19 + base >=4.15 && <4.21 , machines >=0.7.3 && <0.8 , nothunks >=0.1 && <0.4 , profunctors >=3.2 && <5.7 - , singletons-base >=3.0 && <3.3 + , singletons-base >=3.0 , text >=1.2 && <2.1 default-language: Haskell2010 if impl(ghc >= 9.2) @@ -144,7 +146,7 @@ library crem-examples PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.19 + base >=4.15 && <4.21 , crem , profunctors , singletons-base @@ -213,7 +215,7 @@ executable hobbit-game PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.19 + base >=4.15 && <4.21 , crem , crem-examples default-language: Haskell2010 @@ -280,7 +282,7 @@ executable hobbit-map PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.19 + base >=4.15 && <4.21 , crem , crem-examples , text @@ -349,7 +351,7 @@ test-suite crem-doctests PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module -threaded -Wno-unused-packages build-depends: - base >=4.15 && <4.19 + base >=4.15 && <4.21 , crem , crem-examples , doctest-parallel >=0.2.3 && <0.4 @@ -431,7 +433,7 @@ test-suite crem-spec build-tool-depends: hspec-discover:hspec-discover build-depends: - base >=4.15 && <4.19 + base >=4.15 && <4.21 , crem , crem-examples , hspec >=2.7 && <2.12 diff --git a/flake.lock b/flake.lock index 8624f85..fd17f84 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", "owner": "edolstra", "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", "type": "github" }, "original": { @@ -21,11 +21,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -36,11 +36,11 @@ }, "nix-filter": { "locked": { - "lastModified": 1681154353, - "narHash": "sha256-MCJ5FHOlbfQRFwN0brqPbCunLEVw05D/3sRVoNVt2tI=", + "lastModified": 1757882181, + "narHash": "sha256-+cCxYIh2UNalTz364p+QYmWHs0P+6wDhiWR4jDIKQIU=", "owner": "numtide", "repo": "nix-filter", - "rev": "f529f42792ade8e32c4be274af6b6d60857fbee7", + "rev": "59c44d1909c72441144b93cf0f054be7fe764de5", "type": "github" }, "original": { @@ -51,11 +51,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1681303793, - "narHash": "sha256-JEdQHsYuCfRL2PICHlOiH/2ue3DwoxUX7DJ6zZxZXFk=", + "lastModified": 1773122722, + "narHash": "sha256-FIqHByVqxCprNjor1NqF80F2QQoiiyqanNNefdlvOg4=", "owner": "nixos", "repo": "nixpkgs", - "rev": "fe2ecaf706a5907b5e54d979fbde4924d84b65fc", + "rev": "62dc67aa6a52b4364dd75994ec00b51fbf474e50", "type": "github" }, "original": { @@ -67,11 +67,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1681269223, - "narHash": "sha256-i6OeI2f7qGvmLfD07l1Az5iBL+bFeP0RHixisWtpUGo=", + "lastModified": 1688392541, + "narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=", "owner": "nixos", "repo": "nixpkgs", - "rev": "87edbd74246ccdfa64503f334ed86fa04010bab9", + "rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 582c821..bd8e101 100644 --- a/flake.nix +++ b/flake.nix @@ -44,7 +44,7 @@ export GHC_PACKAGE_PATH="dist/package.conf.inplace:$GHC_PACKAGE_PATH" ''; })); - fourmolu = pkgs.haskell.packages.ghc944.fourmolu; + fourmolu = pkgs.haskell.packages.ghc984.fourmolu; }; }; From e6eb04842c3a69fd757cc504e1a08449689d3341 Mon Sep 17 00:00:00 2001 From: harryprayiv Date: Fri, 13 Mar 2026 01:39:39 -0400 Subject: [PATCH 2/8] version bump to 910 --- crem.cabal | 26 ++++++++++++-------------- flake.nix | 4 ++-- nix/haskell-configurations.nix | 2 ++ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/crem.cabal b/crem.cabal index da8c783..bfe0c73 100644 --- a/crem.cabal +++ b/crem.cabal @@ -22,8 +22,6 @@ tested-with: , GHC ==9.2.7 , GHC ==9.4.4 , GHC ==9.6.1 - , GHC ==9.8.4 - , GHC ==9.10.1 extra-source-files: README.md CHANGELOG.md @@ -56,12 +54,12 @@ library PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.21 - , machines >=0.7.3 && <0.8 - , nothunks >=0.1 && <0.4 - , profunctors >=3.2 && <5.7 + base >=4.15 + , machines >=0.7.3 + , nothunks >=0.1 + , profunctors >=3.2 , singletons-base >=3.0 - , text >=1.2 && <2.1 + , text >=1.2 && <2.2 default-language: Haskell2010 if impl(ghc >= 9.2) ghc-options: -Wno-missing-kind-signatures @@ -146,7 +144,7 @@ library crem-examples PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.21 + base >=4.15 , crem , profunctors , singletons-base @@ -215,7 +213,7 @@ executable hobbit-game PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.21 + base >=4.15 , crem , crem-examples default-language: Haskell2010 @@ -282,7 +280,7 @@ executable hobbit-map PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.21 + base >=4.15 , crem , crem-examples , text @@ -351,10 +349,10 @@ test-suite crem-doctests PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module -threaded -Wno-unused-packages build-depends: - base >=4.15 && <4.21 + base >=4.15 , crem , crem-examples - , doctest-parallel >=0.2.3 && <0.4 + , doctest-parallel >=0.2.3 && <0.5 default-language: Haskell2010 if impl(ghc >= 9.2) ghc-options: -Wno-missing-kind-signatures @@ -433,10 +431,10 @@ test-suite crem-spec build-tool-depends: hspec-discover:hspec-discover build-depends: - base >=4.15 && <4.21 + base >=4.15 , crem , crem-examples - , hspec >=2.7 && <2.12 + , hspec >=2.7 && <2.13 , machines , profunctors , singletons-base diff --git a/flake.nix b/flake.nix index bd8e101..0880ce8 100644 --- a/flake.nix +++ b/flake.nix @@ -44,7 +44,7 @@ export GHC_PACKAGE_PATH="dist/package.conf.inplace:$GHC_PACKAGE_PATH" ''; })); - fourmolu = pkgs.haskell.packages.ghc984.fourmolu; + fourmolu = pkgs.haskell.packages.ghc910.fourmolu; }; }; @@ -62,7 +62,7 @@ configurations; # The version of GHC used for default package and development shell. - defaultGhcVersion = "ghc90"; + defaultGhcVersion = "ghc910"; # This is a shell utility that watches source files for changes, and triggers a # command when they change. diff --git a/nix/haskell-configurations.nix b/nix/haskell-configurations.nix index 0f0e1bd..f985fb1 100644 --- a/nix/haskell-configurations.nix +++ b/nix/haskell-configurations.nix @@ -12,4 +12,6 @@ } { ghcVersion = "92"; } { ghcVersion = "94"; } + { ghcVersion = "910"; } + ] From 69be2b894c045b2ab6e0dedcdf1b1faef8c86480 Mon Sep 17 00:00:00 2001 From: harryprayiv Date: Fri, 13 Mar 2026 01:41:34 -0400 Subject: [PATCH 3/8] adding RoleAnnotations where required --- src/Crem/BaseMachine.hs | 7 +++++++ src/Crem/Decider.hs | 8 +++++++- src/Crem/Graph.hs | 4 ++++ src/Crem/Render/RenderFlow.hs | 3 +++ src/Crem/Render/RenderableVertices.hs | 2 ++ src/Crem/StateMachine.hs | 5 ++++- src/Crem/Topology.hs | 17 ++++++++++------- 7 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/Crem/BaseMachine.hs b/src/Crem/BaseMachine.hs index f155262..13a817e 100644 --- a/src/Crem/BaseMachine.hs +++ b/src/Crem/BaseMachine.hs @@ -1,4 +1,5 @@ {-# LANGUAGE DataKinds #-} +{-# LANGUAGE RoleAnnotations #-} -- | A `BaseMachine` is a Mealy machine constrained by a provided `Topology` of -- allowed transitions. @@ -44,6 +45,8 @@ type BaseMachine (output :: Type) = forall m. (Monad m) => BaseMachineT m topology input output +type role BaseMachineT representational nominal representational nominal + -- * Hoist -- | Allows to change the context @m@ where the machine operates to another @@ -113,6 +116,8 @@ instance (Applicative m) => Choice (BaseMachineT m topology) where data InitialState (state :: vertex -> Type) where InitialState :: state vertex -> InitialState state +type role InitialState representational + -- | The result of an action of the state machine. -- An @ActionResult m topology state initialVertex output@ contains an @output@ -- and a @state finalVertex@, where the transition from @initialVertex@ to @@ -130,6 +135,8 @@ data => m (output, state finalVertex) -> ActionResult m topology state initialVertex output +type role ActionResult representational nominal nominal nominal nominal + -- | Allows to change the computational context of an `ActionResult` from @m@ -- to @n@, given we have a [natural transformation](https://stackoverflow.com/a/58364172/2718064) -- from @m@ to @n@. diff --git a/src/Crem/Decider.hs b/src/Crem/Decider.hs index 1d467ae..306b705 100644 --- a/src/Crem/Decider.hs +++ b/src/Crem/Decider.hs @@ -1,4 +1,6 @@ {-# LANGUAGE DataKinds #-} +{-# LANGUAGE RoleAnnotations #-} +{-# OPTIONS_GHC -Wno-missing-poly-kind-signatures #-} -- | The [Decider pattern](https://thinkbeforecoding.com/post/2021/12/17/functional-event-sourcing-decider) -- allows to easily describe an [aggregate](https://www.domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf) @@ -10,7 +12,7 @@ module Crem.Decider where import Crem.BaseMachine (ActionResult (..), BaseMachine, BaseMachineT (..), InitialState (..)) import Crem.Topology (AllowedTransition, Topology) -import Data.Foldable (foldl') +-- import Data.Foldable (foldl') import "base" Data.Kind (Type) -- | A @Decider topology input output@ is a Decider which receives inputs of @@ -42,6 +44,8 @@ data -> EvolutionResult topology state initialVertex output } +type role Decider nominal representational representational + -- | A smart wrapper over the machine state, which allows to enforce that only -- transitions allowed by the @topology@ are actually performed. data @@ -56,6 +60,8 @@ data => state finalVertex -> EvolutionResult topology state initialVertex output +type role EvolutionResult nominal representational nominal phantom + -- | translate a `Decider` into a `BaseMachine` deciderMachine :: Decider topology input output diff --git a/src/Crem/Graph.hs b/src/Crem/Graph.hs index 03f14ad..2f2339f 100644 --- a/src/Crem/Graph.hs +++ b/src/Crem/Graph.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE RoleAnnotations #-} + -- | A simple data structure to describe a directed graph module Crem.Graph where @@ -12,6 +14,8 @@ newtype Graph a = Graph [(a, a)] deriving stock (Eq, Show) deriving newtype (NoThunks) +type role Graph representational + -- | The product graph. -- It has as vertices the product of the set of vertices of the initial graph. -- It has as edge from @(a1, b1)@ to @(a2, b2)@ if and only if there is an edge diff --git a/src/Crem/Render/RenderFlow.hs b/src/Crem/Render/RenderFlow.hs index 4b3d118..81994ed 100644 --- a/src/Crem/Render/RenderFlow.hs +++ b/src/Crem/Render/RenderFlow.hs @@ -1,5 +1,6 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RoleAnnotations #-} -- | Rendering just the state space of a state machine might be sometimes -- limiting. @@ -21,6 +22,8 @@ data TreeMetadata a | BinaryLabel (TreeMetadata a) (TreeMetadata a) deriving stock (Show) +type role TreeMetadata representational + instance NoThunks a => NoThunks (TreeMetadata a) where showTypeOf _ = "TreeMetadata" wNoThunks ctxt tm = diff --git a/src/Crem/Render/RenderableVertices.hs b/src/Crem/Render/RenderableVertices.hs index 4a0b023..c818926 100644 --- a/src/Crem/Render/RenderableVertices.hs +++ b/src/Crem/Render/RenderableVertices.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DerivingVia #-} {-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE RoleAnnotations #-} -- | The `RenderableVertices` class describes which values of type @a@ should -- be rendered when drawing a graph (or a topology) with vertices of type @a@ @@ -22,6 +23,7 @@ class RenderableVertices a where -- `Enum` and `Bounded`, then `AllVertices a` has an instance of -- `RenderableVertices` which lists all the terms of type @a@. newtype AllVertices a = AllVertices a +type role AllVertices representational instance (Enum a, Bounded a) => RenderableVertices (AllVertices a) where vertices :: [AllVertices a] diff --git a/src/Crem/StateMachine.hs b/src/Crem/StateMachine.hs index 3baf2b2..23ab3ed 100644 --- a/src/Crem/StateMachine.hs +++ b/src/Crem/StateMachine.hs @@ -1,6 +1,7 @@ -{-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE RoleAnnotations #-} -- | This is the main module of the whole library. It defines the central -- `StateMachineT` type, which allows us to create composable state machines. @@ -77,6 +78,8 @@ data StateMachineT m input output where -> StateMachineT m b (n c) -> StateMachineT m a (n c) +type role StateMachineT representational nominal nominal + instance NoThunks (StateMachineT m input output) where showTypeOf _ = "StateMachineT" wNoThunks ctxt sm = diff --git a/src/Crem/Topology.hs b/src/Crem/Topology.hs index 7a238ce..29152cf 100644 --- a/src/Crem/Topology.hs +++ b/src/Crem/Topology.hs @@ -1,13 +1,14 @@ {-# LANGUAGE DataKinds #-} +{-# LANGUAGE RoleAnnotations #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeAbstractions #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wredundant-constraints {-# OPTIONS_GHC -Wno-redundant-constraints #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunticked-promoted-constructors {-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunused-type-patterns {-# OPTIONS_GHC -Wno-unused-type-patterns #-} +{-# OPTIONS_GHC -Wno-missing-role-annotations #-} +{-# OPTIONS_GHC -Wno-missing-poly-kind-signatures #-} -- | A `Topology` is a list of allowed transition for a state machine. -- We are using it to enforce that only allowed transitions could be performed. @@ -62,8 +63,10 @@ data AllowTransition (topology :: Topology vertex) (initial :: vertex) (final :: -- | If we know that we have an edge from @a@ to @b@ in @map@, -- then we also have an edge from @a@ to @b@ if we add another vertex AllowAddingVertex - :: AllowTransition ('Topology map) a b - -> AllowTransition ('Topology (x ': map)) a b + :: AllowTransition ('Topology tmap) a b + -> AllowTransition ('Topology (x ': tmap)) a b + +type role AllowTransition nominal nominal nominal instance NoThunks (AllowTransition topology initial final) where showTypeOf _ = "AllowTransition" @@ -87,9 +90,9 @@ instance {-# INCOHERENT #-} (AllowedTransition ('Topology ('(a, l1) ': l2)) a b) allowsTransition = AllowAddingEdge (allowsTransition :: AllowTransition ('Topology ('(a, l1) ': l2)) a b) -instance {-# INCOHERENT #-} (AllowedTransition ('Topology map) a b) => AllowedTransition ('Topology (x ': map)) a b where +instance {-# INCOHERENT #-} (AllowedTransition ('Topology tmap) a b) => AllowedTransition ('Topology (x ': tmap)) a b where allowsTransition = - AllowAddingVertex (allowsTransition :: AllowTransition ('Topology map) a b) + AllowAddingVertex (allowsTransition :: AllowTransition ('Topology tmap) a b) instance {-# INCOHERENT #-} AllowedTransition topology a a where allowsTransition = AllowIdentityEdge From 093297505b4f98a7e08bb0f24f426e65378061b7 Mon Sep 17 00:00:00 2001 From: harryprayiv Date: Fri, 13 Mar 2026 01:45:01 -0400 Subject: [PATCH 4/8] bypass missing-poly-kind-signatures and-role-annotations warnings --- examples/Crem/Example/Cart/Aggregate.hs | 6 +++--- examples/Crem/Example/Cart/Shipping.hs | 8 +++----- examples/Crem/Example/LockDoor.hs | 7 +++---- examples/Crem/Example/RiskManager/Aggregate.hs | 6 +++--- examples/Crem/Example/RiskManager/Projection.hs | 8 +++----- examples/Crem/Example/TheHobbit.hs | 6 +++--- examples/Crem/Example/TriangularMachine.hs | 3 +++ examples/Crem/Example/Uno.hs | 7 +++---- 8 files changed, 24 insertions(+), 27 deletions(-) diff --git a/examples/Crem/Example/Cart/Aggregate.hs b/examples/Crem/Example/Cart/Aggregate.hs index 2a503cb..8b51127 100644 --- a/examples/Crem/Example/Cart/Aggregate.hs +++ b/examples/Crem/Example/Cart/Aggregate.hs @@ -1,13 +1,13 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeAbstractions #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wmissing-deriving-strategies {-# OPTIONS_GHC -Wno-missing-deriving-strategies #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunticked-promoted-constructors +{-# OPTIONS_GHC -Wno-missing-poly-kind-signatures #-} +{-# OPTIONS_GHC -Wno-missing-role-annotations #-} {-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunused-type-patterns {-# OPTIONS_GHC -Wno-unused-type-patterns #-} module Crem.Example.Cart.Aggregate where diff --git a/examples/Crem/Example/Cart/Shipping.hs b/examples/Crem/Example/Cart/Shipping.hs index b508ead..0c5fc0d 100644 --- a/examples/Crem/Example/Cart/Shipping.hs +++ b/examples/Crem/Example/Cart/Shipping.hs @@ -1,15 +1,13 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeAbstractions #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wmissing-deriving-strategies {-# OPTIONS_GHC -Wno-missing-deriving-strategies #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wredundant-constraints -{-# OPTIONS_GHC -Wno-redundant-constraints #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunticked-promoted-constructors +{-# OPTIONS_GHC -Wno-missing-poly-kind-signatures #-} +{-# OPTIONS_GHC -Wno-missing-role-annotations #-} {-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunused-type-patterns {-# OPTIONS_GHC -Wno-unused-type-patterns #-} module Crem.Example.Cart.Shipping where diff --git a/examples/Crem/Example/LockDoor.hs b/examples/Crem/Example/LockDoor.hs index 8154e4e..eb26913 100644 --- a/examples/Crem/Example/LockDoor.hs +++ b/examples/Crem/Example/LockDoor.hs @@ -1,15 +1,14 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeAbstractions #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wall-missed-specialisations {-# OPTIONS_GHC -Wno-all-missed-specialisations #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wmissing-deriving-strategies {-# OPTIONS_GHC -Wno-missing-deriving-strategies #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunticked-promoted-constructors +{-# OPTIONS_GHC -Wno-missing-poly-kind-signatures #-} +{-# OPTIONS_GHC -Wno-missing-role-annotations #-} {-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunused-type-patterns {-# OPTIONS_GHC -Wno-unused-type-patterns #-} module Crem.Example.LockDoor where diff --git a/examples/Crem/Example/RiskManager/Aggregate.hs b/examples/Crem/Example/RiskManager/Aggregate.hs index 285c7b0..e7c4387 100644 --- a/examples/Crem/Example/RiskManager/Aggregate.hs +++ b/examples/Crem/Example/RiskManager/Aggregate.hs @@ -1,13 +1,13 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeAbstractions #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wmissing-deriving-strategies {-# OPTIONS_GHC -Wno-missing-deriving-strategies #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunticked-promoted-constructors +{-# OPTIONS_GHC -Wno-missing-poly-kind-signatures #-} +{-# OPTIONS_GHC -Wno-missing-role-annotations #-} {-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunused-type-patterns {-# OPTIONS_GHC -Wno-unused-type-patterns #-} module Crem.Example.RiskManager.Aggregate where diff --git a/examples/Crem/Example/RiskManager/Projection.hs b/examples/Crem/Example/RiskManager/Projection.hs index 769f64c..a75b07a 100644 --- a/examples/Crem/Example/RiskManager/Projection.hs +++ b/examples/Crem/Example/RiskManager/Projection.hs @@ -1,16 +1,14 @@ {-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeAbstractions #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wmissing-deriving-strategies {-# OPTIONS_GHC -Wno-missing-deriving-strategies #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunticked-promoted-constructors +{-# OPTIONS_GHC -Wno-missing-poly-kind-signatures #-} +{-# OPTIONS_GHC -Wno-missing-role-annotations #-} {-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunused-type-patterns {-# OPTIONS_GHC -Wno-unused-type-patterns #-} - module Crem.Example.RiskManager.Projection where import Crem.BaseMachine diff --git a/examples/Crem/Example/TheHobbit.hs b/examples/Crem/Example/TheHobbit.hs index b41349e..b38e737 100644 --- a/examples/Crem/Example/TheHobbit.hs +++ b/examples/Crem/Example/TheHobbit.hs @@ -1,13 +1,13 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeAbstractions #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wmissing-deriving-strategies {-# OPTIONS_GHC -Wno-missing-deriving-strategies #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunticked-promoted-constructors +{-# OPTIONS_GHC -Wno-missing-poly-kind-signatures #-} +{-# OPTIONS_GHC -Wno-missing-role-annotations #-} {-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunused-type-patterns {-# OPTIONS_GHC -Wno-unused-type-patterns #-} -- | This is a small adventure game based on [The Hobbit](https://en.wikipedia.org/wiki/The_Hobbit_(1982_video_game)) diff --git a/examples/Crem/Example/TriangularMachine.hs b/examples/Crem/Example/TriangularMachine.hs index 26ab66c..9685261 100644 --- a/examples/Crem/Example/TriangularMachine.hs +++ b/examples/Crem/Example/TriangularMachine.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} +{-# LANGUAGE RoleAnnotations #-} module Crem.Example.TriangularMachine where @@ -9,6 +10,8 @@ import Crem.StateMachine (StateMachine, unrestrictedMachine) data TriangularState (a :: ()) where OnlyState :: Int -> TriangularState '() +type role TriangularState nominal + triangular :: StateMachine Int Int triangular = unrestrictedMachine diff --git a/examples/Crem/Example/Uno.hs b/examples/Crem/Example/Uno.hs index 923a756..1c003c6 100644 --- a/examples/Crem/Example/Uno.hs +++ b/examples/Crem/Example/Uno.hs @@ -3,15 +3,14 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeAbstractions #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wmissing-deriving-strategies {-# OPTIONS_GHC -Wno-missing-deriving-strategies #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunrecognised-pragmas +{-# OPTIONS_GHC -Wno-missing-poly-kind-signatures #-} +{-# OPTIONS_GHC -Wno-missing-role-annotations #-} {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunticked-promoted-constructors {-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-} --- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunused-type-patterns {-# OPTIONS_GHC -Wno-unused-type-patterns #-} -- | Porting of https://github.com/thinkbeforecoding/UnoCore/blob/solution/Uno/Game.fs From 6677a3eed45a69a7d31738f73d429aa09ac8679a Mon Sep 17 00:00:00 2001 From: harryprayiv Date: Fri, 13 Mar 2026 11:25:54 -0400 Subject: [PATCH 5/8] doctest fixes (not really working properly right now) --- doctest/Main.hs | 5 +- examples/Crem/Example/TwoSwitchesGate.hs | 322 +++++++++++++++++++++++ 2 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 examples/Crem/Example/TwoSwitchesGate.hs diff --git a/doctest/Main.hs b/doctest/Main.hs index 5d32360..79c5705 100644 --- a/doctest/Main.hs +++ b/doctest/Main.hs @@ -11,5 +11,6 @@ main = do cremLib <- extractCabalLibrary cremPackage cremExamplesLib <- extractSpecificCabalLibrary (Just "crem-examples") cremPackage let - wholeCremLib = mergeLibraries [cremLib, cremExamplesLib] - mainFromLibrary wholeCremLib args + base = mergeLibraries [cremLib, cremExamplesLib] + wholeCremLib = base + { = "-package-id" : "crem-examples" : base } \ No newline at end of file diff --git a/examples/Crem/Example/TwoSwitchesGate.hs b/examples/Crem/Example/TwoSwitchesGate.hs new file mode 100644 index 0000000..81cf65c --- /dev/null +++ b/examples/Crem/Example/TwoSwitchesGate.hs @@ -0,0 +1,322 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeAbstractions #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE UndecidableInstances #-} +{-# OPTIONS_GHC -Wno-missing-deriving-strategies #-} +{-# OPTIONS_GHC -Wno-missing-poly-kind-signatures #-} +{-# OPTIONS_GHC -Wno-missing-role-annotations #-} +{-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-} +{-# OPTIONS_GHC -Wno-unused-type-patterns #-} + +module Crem.Example.TwoSwitchesGate where + +import "crem" Crem.BaseMachine +import "crem" Crem.Render.Render +import "crem" Crem.Render.RenderableVertices (AllVertices(..), RenderableVertices) +import "crem" Crem.Render.RenderFlow +import "crem" Crem.StateMachine +import "crem" Crem.Topology +import "base" Data.Functor.Identity +import "profunctors" Data.Profunctor +import "singletons-base" Data.Singletons.Base.TH +import "text" Data.Text (pack) + +{- +We would like to implement a gate opening mechanism controlled by two switches. +We would like the gate to open only when the two switches are on. + +We would like to implement this by composing several small state machines: one +for every switch, one for making sure that we actually receive the right message +from both switches, and one for actually opening the gate. + +Let's start with the switch. + +The first thing we need to do is to define the topology of our machine, meaning +the allowed transitions in its state space. + +For a switch, there are only two states. Either the switch is on or it is off. + +Moreover, we want those switches to be usable only once, and therefore we want +to forbid the transition from the `on` to the `off` position. In other terms, +we allow only to go from the `off` position to the `on` position. +-} + +$( singletons + [d| + data SwitchVertex + = SwitchIsOn + | SwitchIsOff + deriving stock (Eq, Show, Bounded, Enum) + + switchTopology :: Topology SwitchVertex + switchTopology = Topology + [(SwitchIsOff, [ SwitchIsOn ])] + |] + ) + +{- +Notice that we need to wrap this in `singletons` because we will soon need to +use this data type as a kind, to store information in the type of our state +machines. + +We need also an instance of `RenderableVertices SwitchVertex` to decide which +vertices to render for our machine. To obtain that, we use `deriving via` +together with the `AllVertices` newtype. +-} + +deriving via AllVertices SwitchVertex instance RenderableVertices SwitchVertex + +{- +Next we need to define which data every vertex of our topology should contain. +To express that we use a generalized algebraic data type indexed with +`SwitchVertex`. +-} + +data SwitchState (vertex :: SwitchVertex) where + OnState :: SwitchState 'SwitchIsOn + OffState :: SwitchState 'SwitchIsOff + +{- +In this case, for every vertex there is just one possible state. + +At this point we need to define which inputs our machine should handle and which +outputs it should emit. In the case there is only one meaningful input, the +request of turning on the switch, and one meaningful output, the notification +that the switch has been turned on. +-} + +data SwitchInput = TurnOn + +data SwitchOutput = TurnedOn + deriving stock Show + +instance Semigroup SwitchOutput where + TurnedOn <> TurnedOn = TurnedOn + +{- +At this point we can actually implement our switch as a `BaseMachine`. +-} + +switch :: () -> BaseMachine SwitchTopology SwitchInput SwitchOutput +switch _ = + BaseMachineT + { initialState = InitialState OffState + , action = \case + OnState -> \_ -> pureResult TurnedOn OnState + OffState -> \_ -> pureResult TurnedOn OnState + } + +{- +We start from the `OffState` and every time we receive a request to turn the +switch on, we return a message informing the external world that the switch is +turned on and we update the state accordingly if needed. + +Since we need two separate switches, we can create them by invoking the +`switch` function twice. +-} + +switch1 :: BaseMachine SwitchTopology SwitchInput SwitchOutput +switch1 = switch () + +switch2 :: BaseMachine SwitchTopology SwitchInput SwitchOutput +switch2 = switch () + +{- +This concludes the implementation of our switch machine. Next, we would like to +implement a machine which receives as inputs the output of two switches and +emits a message whenever both the switches have been turned on. + +Again, we need to start thinking about the topology of our machine. Since we +need to track the state of the two switches, we will have four vertices. +-} + +$( singletons + [d| + data BothVertex + = NoSwitchOn + | OnlyFirstSwitchOn + | OnlySecondSwitchOn + | BothSwitchesOn + deriving (Eq, Show, Enum, Bounded) + + bothTopology :: Topology BothVertex + bothTopology = Topology + [ (NoSwitchOn, [OnlyFirstSwitchOn, OnlySecondSwitchOn]) + , (OnlyFirstSwitchOn, [BothSwitchesOn]) + , (OnlySecondSwitchOn, [BothSwitchesOn]) + ] + |] + ) + +deriving via AllVertices BothVertex instance RenderableVertices BothVertex + +{- +The topology again constrains the machine with the invariant that we can only +turn on switches. + +Next we need to define the state space, assigning a data type to every vertex +in the topology. In this case we don't have the need to attach data to our +vertices so we can simply define: +-} + +data BothState (vertex :: BothVertex) where + NoSwitchOnState :: BothState 'NoSwitchOn + OnlyFirstSwitchOnState :: BothState 'OnlyFirstSwitchOn + OnlySecondSwitchOnState :: BothState 'OnlySecondSwitchOn + BothSwitchesOnState :: BothState 'BothSwitchesOn + +{- +Before defining the logic of the machine, we need to define its inputs and +outputs. Since we would like it to monitor the outputs of both switches, its +input type could be: +-} + +type BothInput = Either SwitchOutput SwitchOutput + +{- +Its output instead will be a potential message to actually open the gate. +-} + +data OpenGate = OpenGate + +type BothOutput = Maybe OpenGate + +{- +And eventually we can define the logic of our state machine. +-} + +bothMachine :: BaseMachine BothTopology BothInput BothOutput +bothMachine = + BaseMachineT + { initialState = InitialState NoSwitchOnState + , action = \case + NoSwitchOnState -> \case + Left _ -> pureResult Nothing OnlyFirstSwitchOnState + Right _ -> pureResult Nothing OnlySecondSwitchOnState + OnlyFirstSwitchOnState -> \case + Left _ -> pureResult Nothing OnlyFirstSwitchOnState + Right _ -> pureResult (Just OpenGate) BothSwitchesOnState + OnlySecondSwitchOnState -> \case + Left _ -> pureResult (Just OpenGate) BothSwitchesOnState + Right _ -> pureResult Nothing OnlySecondSwitchOnState + BothSwitchesOnState -> \_ -> pureResult Nothing BothSwitchesOnState + } + +{- +The last machine that we need is one representing the actual gate. Since the +logic is exactly the same as the one of the switches, we can actually reuse +what we defined above. +-} + +gate :: BaseMachine SwitchTopology SwitchInput SwitchOutput +gate = switch () + +{- +Now we have all the machines we wanted and we need to connect them +appropriately. + +We have the two switches which produce a `SwitchOutput` and the `bothMachine` +which accepts inputs of type `Either SwitchOutput SwitchOutput`. + +We need to pair up the two switches, first, and then connect them to the +`bothMachine`. We need to pair the two switches in a way that allows us to +decide whether to run one or the other: this is exactly what the `Alternative` +constructor of the `StateMachineT` data type allows us to do. +-} + +switches :: StateMachine (Either SwitchInput SwitchInput) (Either SwitchOutput SwitchOutput) +switches = Basic switch1 `Alternative` Basic switch2 + +{- +Notice that we had to wrap our `switch` machines with `Basic` to turn them into +`StateMachine`s, which is the more composable type used by `Alternative`. + +Now we have the output of `switches` which coincides with the input of +`bothMachine`, and therefore we can pass every output we get from `switches` to +`bothMachine`. We use the `Sequential` constructor exactly for this. +-} + +bothSwitches :: StateMachine (Either SwitchInput SwitchInput) BothOutput +bothSwitches = switches `Sequential` Basic bothMachine + +{- +Now we have a machine which emits `BothOutput = Maybe OpenGate`. Our `gate` +machine on the other hand accepts inputs of type `SwitchInput`. To connect +those, we need to do some adjusting. + +First, we can translate an `OpenGate` into a `SwitchInput`. +-} + +openGateToSwitchInput :: OpenGate -> SwitchInput +openGateToSwitchInput OpenGate = TurnOn + +{- +And we can use this function to adapt our `gate` machine so that it accepts +`OpenGate` as input. +-} + +gate' :: BaseMachine SwitchTopology OpenGate SwitchOutput +gate' = lmap openGateToSwitchInput gate + +{- +Still `bothSwitches` emits values of type `Maybe OpenGate`. We could lift our +`gate'` machine to `Maybe OpenGate` inputs using the `maybeM` combinator. +-} + +maybeGate :: BaseMachine SwitchTopology (Maybe OpenGate) (Maybe SwitchOutput) +maybeGate = maybeM gate' + +{- +At this point we could conclude our composition, joining together `bothMachine` +and `maybeGate`. +-} + +gateMachine :: StateMachine (Either SwitchInput SwitchInput) (Maybe SwitchOutput) +gateMachine = bothSwitches `Sequential` Basic maybeGate + +{- +Now we have a single machine which describes our whole flow. + +The first thing we can do is actually execute it using the `runMultiple` +function. + +We can try to turn on both switches and verify that the gate actually opened: +-} + +-- | +-- >>> openedGate +-- Just TurnedOn +openedGate :: Maybe SwitchOutput +openedGate = fst . runIdentity $ runMultiple gateMachine [Left TurnOn, Right TurnOn] + +{- +Or we can turn just the first switch several times without opening the gate: +-} + +-- | +-- >>> closedGate +-- Nothing +closedGate :: Maybe SwitchOutput +closedGate = fst . runIdentity $ runMultiple gateMachine [Left TurnOn, Left TurnOn, Left TurnOn] + +{- +The other thing we can do is render a diagram representing how the `gateMachine` +works, displaying the flow of the machine and the state space for every step. +-} + +-- | +-- >>> gateFlow +-- Right "state switch1 {\nswitch1_SwitchIsOn\nswitch1_SwitchIsOff\nswitch1_SwitchIsOff --> switch1_SwitchIsOn\n}\nstate switch2 {\nswitch2_SwitchIsOn\nswitch2_SwitchIsOff\nswitch2_SwitchIsOff --> switch2_SwitchIsOn\n}\nstate fork_choice_switch1switch2 <>\nstate join_choice_switch1switch2 <>\nfork_choice_switch1switch2 --> switch1\nfork_choice_switch1switch2 --> switch2\nswitch1 --> join_choice_switch1switch2\nswitch2 --> join_choice_switch1switch2\nstate both {\nboth_NoSwitchOn\nboth_OnlyFirstSwitchOn\nboth_OnlySecondSwitchOn\nboth_BothSwitchesOn\nboth_NoSwitchOn --> both_OnlyFirstSwitchOn\nboth_NoSwitchOn --> both_OnlySecondSwitchOn\nboth_OnlyFirstSwitchOn --> both_BothSwitchesOn\nboth_OnlySecondSwitchOn --> both_BothSwitchesOn\n}\njoin_choice_switch1switch2 --> both\nstate gate {\ngate_SwitchIsOn\ngate_SwitchIsOff\ngate_SwitchIsOff --> gate_SwitchIsOn\n}\nboth --> gate" +gateFlow :: Either String Mermaid +gateFlow = (\(mermaid, _, _) -> mermaid) <$> + renderFlow + (BinaryLabel + (BinaryLabel + (BinaryLabel + (LeafLabel . MachineLabel . pack $ "switch1") + (LeafLabel . MachineLabel . pack $ "switch2")) + (LeafLabel . MachineLabel . pack $ "both")) + (LeafLabel . MachineLabel . pack $ "gate")) + (gateMachine @Identity) \ No newline at end of file From 4e124757512402ded4065e515a0afd8c72e02af3 Mon Sep 17 00:00:00 2001 From: harryprayiv Date: Fri, 13 Mar 2026 11:30:41 -0400 Subject: [PATCH 6/8] relaxed version boundaries --- crem.cabal | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/crem.cabal b/crem.cabal index bfe0c73..5843bcb 100644 --- a/crem.cabal +++ b/crem.cabal @@ -54,12 +54,12 @@ library PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 - , machines >=0.7.3 - , nothunks >=0.1 - , profunctors >=3.2 - , singletons-base >=3.0 - , text >=1.2 && <2.2 + base >=4.15 && <4.19 + , machines >=0.7.3 && <0.8 + , nothunks >=0.1 && <0.4 + , profunctors >=3.2 && <5.7 + , singletons-base >=3.0 && <3.3 + , text >=1.2 && <2.1 default-language: Haskell2010 if impl(ghc >= 9.2) ghc-options: -Wno-missing-kind-signatures @@ -144,7 +144,7 @@ library crem-examples PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 + base >=4.15 && <4.19 , crem , profunctors , singletons-base @@ -213,7 +213,7 @@ executable hobbit-game PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 + base >=4.15 && <4.19 , crem , crem-examples default-language: Haskell2010 @@ -280,7 +280,7 @@ executable hobbit-map PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 + base >=4.15 && <4.19 , crem , crem-examples , text @@ -349,10 +349,10 @@ test-suite crem-doctests PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module -threaded -Wno-unused-packages build-depends: - base >=4.15 + base >=4.15 && <4.19 , crem , crem-examples - , doctest-parallel >=0.2.3 && <0.5 + , doctest-parallel >=0.2.3 && <0.4 default-language: Haskell2010 if impl(ghc >= 9.2) ghc-options: -Wno-missing-kind-signatures @@ -431,10 +431,10 @@ test-suite crem-spec build-tool-depends: hspec-discover:hspec-discover build-depends: - base >=4.15 + base >=4.15 && <4.19 , crem , crem-examples - , hspec >=2.7 && <2.13 + , hspec >=2.7 && <2.12 , machines , profunctors , singletons-base From 1776cd2f62aaead5aaff61e849c66d4163868af9 Mon Sep 17 00:00:00 2001 From: harryprayiv Date: Fri, 13 Mar 2026 11:54:01 -0400 Subject: [PATCH 7/8] finally got version bounds correct. Still need to repair doctest. --- crem.cabal | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/crem.cabal b/crem.cabal index 5843bcb..de518cf 100644 --- a/crem.cabal +++ b/crem.cabal @@ -54,12 +54,12 @@ library PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.19 - , machines >=0.7.3 && <0.8 - , nothunks >=0.1 && <0.4 - , profunctors >=3.2 && <5.7 - , singletons-base >=3.0 && <3.3 - , text >=1.2 && <2.1 + base >=4.15 + , machines >=0.7.3 + , nothunks >=0.1 + , profunctors >=3.2 + , singletons-base >=3.0 + , text >=1.2 && <2.2 default-language: Haskell2010 if impl(ghc >= 9.2) ghc-options: -Wno-missing-kind-signatures @@ -144,7 +144,7 @@ library crem-examples PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.19 + base >=4.15 , crem , profunctors , singletons-base @@ -213,7 +213,7 @@ executable hobbit-game PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.19 + base >=4.15 , crem , crem-examples default-language: Haskell2010 @@ -280,7 +280,7 @@ executable hobbit-map PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module build-depends: - base >=4.15 && <4.19 + base >=4.15 , crem , crem-examples , text @@ -349,10 +349,10 @@ test-suite crem-doctests PackageImports ghc-options: -Weverything -Wno-safe -Wno-unsafe -Wno-missing-safe-haskell-mode -Wno-implicit-prelude -Wno-missing-export-lists -Wno-missing-home-modules -Wno-missing-import-lists -Wno-all-missed-specialisations -Wno-prepositive-qualified-module -threaded -Wno-unused-packages build-depends: - base >=4.15 && <4.19 + base >=4.15 , crem , crem-examples - , doctest-parallel >=0.2.3 && <0.4 + , doctest-parallel >=0.2.3 default-language: Haskell2010 if impl(ghc >= 9.2) ghc-options: -Wno-missing-kind-signatures @@ -431,10 +431,10 @@ test-suite crem-spec build-tool-depends: hspec-discover:hspec-discover build-depends: - base >=4.15 && <4.19 + base >=4.15 , crem , crem-examples - , hspec >=2.7 && <2.12 + , hspec >=2.7 , machines , profunctors , singletons-base From 4a9a1ee353e6790267c10c96d5372efc522e9d1a Mon Sep 17 00:00:00 2001 From: harryprayiv Date: Wed, 18 Mar 2026 11:13:16 -0400 Subject: [PATCH 8/8] Fix doctests for GHC 9.10.3 by upgrading to cabal-version 3.0, using qualified internal library syntax, and rewriting the doctest runner to inject the crem-examples package-id directly into evalGhciArgs via runModules. --- crem.cabal | 12 +++++++----- doctest/Main.hs | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/crem.cabal b/crem.cabal index de518cf..0b5cac5 100644 --- a/crem.cabal +++ b/crem.cabal @@ -1,4 +1,4 @@ -cabal-version: 2.0 +cabal-version: 3.0 -- This file has been generated from package.yaml by hpack version 0.38.3. -- @@ -215,7 +215,7 @@ executable hobbit-game build-depends: base >=4.15 , crem - , crem-examples + , crem:crem-examples default-language: Haskell2010 if impl(ghc >= 9.2) ghc-options: -Wno-missing-kind-signatures @@ -282,7 +282,7 @@ executable hobbit-map build-depends: base >=4.15 , crem - , crem-examples + , crem:crem-examples , text default-language: Haskell2010 if impl(ghc >= 9.2) @@ -351,8 +351,10 @@ test-suite crem-doctests build-depends: base >=4.15 , crem - , crem-examples + , crem:crem-examples + , directory , doctest-parallel >=0.2.3 + , filepath default-language: Haskell2010 if impl(ghc >= 9.2) ghc-options: -Wno-missing-kind-signatures @@ -433,7 +435,7 @@ test-suite crem-spec build-depends: base >=4.15 , crem - , crem-examples + , crem:crem-examples , hspec >=2.7 , machines , profunctors diff --git a/doctest/Main.hs b/doctest/Main.hs index 79c5705..a3732fc 100644 --- a/doctest/Main.hs +++ b/doctest/Main.hs @@ -1,16 +1,44 @@ +{-# LANGUAGE ImplicitParams #-} + module Main where -import "base" System.Environment (getArgs) -import "doctest-parallel" Test.DocTest +import "base" Control.Monad (unless) +import "base" Data.List (isPrefixOf, isInfixOf) +import "base" System.Exit (exitFailure) +import "directory" System.Directory (getCurrentDirectory, listDirectory) +import "filepath" System.FilePath (()) +import "doctest-parallel" Test.DocTest (isSuccess, setSeed) import "doctest-parallel" Test.DocTest.Helpers +import "doctest-parallel" Test.DocTest.Internal.Logging (LogLevel (..)) +import "doctest-parallel" Test.DocTest.Internal.Options (defaultModuleConfig) +import "doctest-parallel" Test.DocTest.Internal.Runner (runModules) main :: IO () main = do - args <- getArgs cremPackage <- findCabalPackage "crem" cremLib <- extractCabalLibrary cremPackage cremExamplesLib <- extractSpecificCabalLibrary (Just "crem-examples") cremPackage + let wholeCremLib = mergeLibraries [cremLib, cremExamplesLib] + pkgId <- findCremExamplesId let - base = mergeLibraries [cremLib, cremExamplesLib] - wholeCremLib = base - { = "-package-id" : "crem-examples" : base } \ No newline at end of file + (includeArgs, allModules, otherGhciArgs) = libraryToGhciArgs wholeCremLib + evalGhciArgs = otherGhciArgs ++ ["-package-id", pkgId] + parseGhcArgs = includeArgs ++ otherGhciArgs + modConfig <- let ?verbosity = Info in setSeed defaultModuleConfig + summary <- let ?verbosity = Info in runModules modConfig Nothing True parseGhcArgs evalGhciArgs allModules + unless (isSuccess summary) exitFailure + +findCremExamplesId :: IO String +findCremExamplesId = do + dir <- getCurrentDirectory + files <- listDirectory dir + let envFiles = filter (isPrefixOf ".ghc.environment.") files + case envFiles of + [] -> error "No .ghc.environment file found; run cabal build first" + (f:_) -> do + contents <- readFile (dir f) + let pkgIdLines = filter (isPrefixOf "package-id") (lines contents) + examplesLines = filter (isInfixOf "crem-examples") pkgIdLines + case examplesLines of + [] -> error "Could not find crem-examples package-id in .ghc.environment file" + (l:_) -> pure (drop (length "package-id ") l) \ No newline at end of file