packages feed

numhask 0.12.1.0 → 0.13.3.0

raw patch · 20 files changed

Files

ChangeLog.md view
@@ -1,3 +1,40 @@+0.13.3.0+===++- Added `Read` instance for `Polar` in `NumHask.Algebra.Metric`.+- Added `NumHask.Algebra.Tropical` with the `MinPlus` tropical semiring.+- Added `StarSemiring` and `KleeneAlgebra` instances for `Bool`.+- Added `Magma`, `Unital` and `Idempotent` instances for `Bool`.+- Documented `StarSemiring` and `KleeneAlgebra` laws with the Conway equations.++0.13.2.1+===++- removed doctest-parallel test suite, use cabal-docspec in CI instead+- updated CI to use cabal-docspec 0.0.0.20250606++0.13.2+===++- GHC 9.14.1 support+- simplified Cabal stanzas to best practice template+- fixed asinh bug in Field module++0.13.1+===++- added Data instances+++0.13+===++- added modF, divF and divModF as field versions of modulo and diviso Integral functions.+- fixed bug in EuclideanPair log function.+- BoundedJoinSemiLattice becomes LowerBounded+- BoundedMeetSemiLattice becomes UpperBounded+- switch to GHC2024+ 0.12.1 === 
numhask.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: numhask-version: 0.12.1.0+version: 0.13.3.0 license: BSD-3-Clause license-file: LICENSE copyright: Tony Day (c) 2016@@ -11,79 +11,67 @@ bug-reports: https://github.com/tonyday567/numhask/issues synopsis: A numeric class hierarchy. description:-    This package provides alternative numeric classes over Prelude.+  This package provides alternative numeric classes over Prelude. -    The numeric class constellation looks somewhat like:+  The numeric class constellation looks somewhat like: -    ![nh](docs/other/nh12.svg)+  ![nh](docs/other/nh12.svg) -    == Usage+  == Usage -    >>> {-# LANGUAGE GHC2021 #-}-    >>> {-# LANGUAGE RebindableSyntax #-}-    >>> import NumHask.Prelude+  >>> {-# LANGUAGE GHC2024 #-}+  >>> {-# LANGUAGE RebindableSyntax #-}+  >>> import NumHask.Prelude -    See "NumHask" for a detailed overview.+  See "NumHask" for a detailed overview.  build-type: Simple tested-with:-    , GHC == 9.10.1-    , GHC == 9.6.5-    , GHC == 9.8.2+  ghc ==9.10.3+  ghc ==9.12.2+  ghc ==9.14.1+ extra-doc-files:-    ChangeLog.md-    other/*.svg-    readme.md+  ChangeLog.md+  other/*.svg+  readme.md  source-repository head-    type: git-    location: https://github.com/tonyday567/numhask+  type: git+  location: https://github.com/tonyday567/numhask  common ghc-options-stanza-    ghc-options:-        -Wall-        -Wcompat-        -Widentities-        -Wincomplete-record-updates-        -Wincomplete-uni-patterns-        -Wpartial-fields-        -Wredundant-constraints--common ghc2021-stanza-    default-language: GHC2021+  ghc-options:+    -Wall+    -Wcompat+    -Wincomplete-record-updates+    -Wincomplete-uni-patterns+    -Wredundant-constraints  library-    import: ghc-options-stanza-    import: ghc2021-stanza-    hs-source-dirs: src-    build-depends: , base >=4.14 && <5-    exposed-modules:-        NumHask-        NumHask.Algebra.Action-        NumHask.Algebra.Additive-        NumHask.Algebra.Field-        NumHask.Algebra.Group-        NumHask.Algebra.Lattice-        NumHask.Algebra.Metric-        NumHask.Algebra.Multiplicative-        NumHask.Algebra.Ring-        NumHask.Data.Complex-        NumHask.Data.Integral-        NumHask.Data.Positive-        NumHask.Data.Rational-        NumHask.Data.Wrapped-        NumHask.Exception-        NumHask.Prelude-    default-extensions: RebindableSyntax+  import: ghc-options-stanza+  default-language: GHC2024+  hs-source-dirs: src+  build-depends: base >=4.14 && <5+  exposed-modules:+    NumHask+    NumHask.Algebra.Action+    NumHask.Algebra.Additive+    NumHask.Algebra.Field+    NumHask.Algebra.Group+    NumHask.Algebra.Lattice+    NumHask.Algebra.Metric+    NumHask.Algebra.Multiplicative+    NumHask.Algebra.Patterns+    NumHask.Algebra.Ring+    NumHask.Algebra.Tropical+    NumHask.Data.Complex+    NumHask.Data.Integral+    NumHask.Data.Positive+    NumHask.Data.Rational+    NumHask.Data.Wrapped+    NumHask.Exception+    NumHask.Prelude -test-suite doctests-    import: ghc2021-stanza-    main-is: doctests.hs-    hs-source-dirs: test-    build-depends:-        , QuickCheck       >=2.14 && <2.16-        , base             >=4.14 && <5-        , doctest-parallel >=0.3 && <0.4-    default-extensions: RebindableSyntax-    ghc-options: -threaded-    type: exitcode-stdio-1.0+  default-extensions: RebindableSyntax+
readme.md view
@@ -2,7 +2,7 @@ ===  [![Hackage](https://img.shields.io/hackage/v/numhask.svg)](https://hackage.haskell.org/package/numhask)-[![Build Status](https://github.com/tonyday567/numhask/workflows/haskell-ci/badge.svg)](https://github.com/tonyday567/numhask/actions?query=workflow%3Ahaskell-ci)+[![build](https://github.com/tonyday567/numhask/actions/workflows/haskell-ci.yml/badge.svg)](https://github.com/tonyday567/numhask/actions/workflows/haskell-ci.yml)  ![](other/nh12.svg) @@ -145,7 +145,7 @@       DivisiveAction,       JoinSemiLattice,       MeetSemiLattice,-      BoundedMeetSemiLattice+      UpperBounded     )     via (Wrapped a) ```
src/NumHask.hs view
@@ -36,6 +36,9 @@     InvolutiveRing (..),     two, +    -- * Tropical+    MinPlus (..),+     -- * Field     Field,     ExpField (..),@@ -45,6 +48,9 @@     negInfinity,     nan,     half,+    modF,+    divF,+    divModF,      -- * Lattice     JoinSemiLattice (..),@@ -53,8 +59,8 @@     MeetSemiLattice (..),     meetLeq,     (</),-    BoundedJoinSemiLattice (..),-    BoundedMeetSemiLattice (..),+    LowerBounded (..),+    UpperBounded (..),      -- * Action     AdditiveAction (..),@@ -66,6 +72,7 @@     DivisiveAction (..),     (/|),     Module,+    TrivialAction (..),      -- * Metric     Basis (..),@@ -89,6 +96,7 @@     (+:),     realPart,     imagPart,+    normSquared,      -- * Integral     Integral (..),@@ -101,6 +109,7 @@     odd,     (^^),     (^),+    (^+),      -- * Rational     Ratio (..),@@ -110,6 +119,8 @@     FromRational (..),     reduce,     gcd,+    numerator,+    denominator,      -- * Exceptions     NumHaskException (..),@@ -123,6 +134,7 @@     Module,     MultiplicativeAction (..),     SubtractiveAction (..),+    TrivialAction (..),     (*|),     (+|),     (-|),@@ -139,16 +151,19 @@     Field,     QuotientField (..),     TrigField (..),+    divF,+    divModF,     half,     infinity,+    modF,     nan,     negInfinity,   ) import NumHask.Algebra.Lattice-  ( BoundedJoinSemiLattice (..),-    BoundedMeetSemiLattice (..),-    JoinSemiLattice (..),+  ( JoinSemiLattice (..),+    LowerBounded (..),     MeetSemiLattice (..),+    UpperBounded (..),     joinLeq,     meetLeq,     (</),@@ -185,7 +200,14 @@     StarSemiring (..),     two,   )-import NumHask.Data.Complex (Complex (..), imagPart, realPart, (+:))+import NumHask.Algebra.Tropical (MinPlus (..))+import NumHask.Data.Complex+  ( Complex (..),+    imagPart,+    normSquared,+    realPart,+    (+:),+  ) import NumHask.Data.Integral   ( FromInt,     FromInteger (..),@@ -196,6 +218,7 @@     even,     odd,     (^),+    (^+),     (^^),   ) import NumHask.Data.Rational@@ -204,7 +227,9 @@     Ratio (..),     Rational,     ToRatio (..),+    denominator,     gcd,+    numerator,     reduce,   ) import NumHask.Exception (NumHaskException (..), throw)
src/NumHask/Algebra/Action.hs view
@@ -13,14 +13,15 @@     DivisiveAction (..),     (/|),     Module,+    TrivialAction (..),   ) where  import Data.Kind (Type)-import NumHask.Algebra.Additive (Additive, Subtractive, negate)-import NumHask.Algebra.Multiplicative (Divisive, Multiplicative, recip)+import NumHask.Algebra.Additive (Additive (..), Subtractive (..))+import NumHask.Algebra.Multiplicative (Divisive (..), Multiplicative (..)) import NumHask.Algebra.Ring (Distributive)-import Prelude (flip)+import Prelude (Eq, Ord, flip)  -- | Additive Action --@@ -110,3 +111,23 @@ -- > a *| zero == zero -- > a *| b == b |* a type Module m = (Distributive (Scalar m), MultiplicativeAction m)++-- | An action of a set of numbers on itself+newtype TrivialAction a = TrivialAction+  { getTrivialAction :: a+  }+  deriving (Eq, Ord, Additive, Subtractive, Multiplicative, Divisive)++instance (Additive a) => AdditiveAction (TrivialAction a) where+  type AdditiveScalar (TrivialAction a) = a+  TrivialAction a |+ b = TrivialAction (a + b)++instance (Subtractive a) => SubtractiveAction (TrivialAction a) where+  TrivialAction a |- b = TrivialAction (a - b)++instance (Multiplicative a) => MultiplicativeAction (TrivialAction a) where+  type Scalar (TrivialAction a) = a+  TrivialAction a |* b = TrivialAction (a * b)++instance (Divisive a) => DivisiveAction (TrivialAction a) where+  TrivialAction a |/ b = TrivialAction (a / b)
src/NumHask/Algebra/Additive.hs view
@@ -102,6 +102,7 @@   zero = 0  instance Subtractive Double where+  (-) = (P.-)   negate = P.negate  instance Additive Float where@@ -109,6 +110,7 @@   zero = 0  instance Subtractive Float where+  (-) = (P.-)   negate = P.negate  instance Additive Int where@@ -116,6 +118,7 @@   zero = 0  instance Subtractive Int where+  (-) = (P.-)   negate = P.negate  instance Additive Integer where@@ -123,6 +126,7 @@   zero = 0  instance Subtractive Integer where+  (-) = (P.-)   negate = P.negate  instance Additive Bool where@@ -134,6 +138,7 @@   zero = 0  instance Subtractive Natural where+  (-) = (P.-)   negate = P.negate  instance Additive Int8 where@@ -141,6 +146,7 @@   zero = 0  instance Subtractive Int8 where+  (-) = (P.-)   negate = P.negate  instance Additive Int16 where@@ -148,6 +154,7 @@   zero = 0  instance Subtractive Int16 where+  (-) = (P.-)   negate = P.negate  instance Additive Int32 where@@ -155,6 +162,7 @@   zero = 0  instance Subtractive Int32 where+  (-) = (P.-)   negate = P.negate  instance Additive Int64 where@@ -162,6 +170,7 @@   zero = 0  instance Subtractive Int64 where+  (-) = (P.-)   negate = P.negate  instance Additive Word where@@ -169,6 +178,7 @@   zero = 0  instance Subtractive Word where+  (-) = (P.-)   negate = P.negate  instance Additive Word8 where@@ -176,6 +186,7 @@   zero = 0  instance Subtractive Word8 where+  (-) = (P.-)   negate = P.negate  instance Additive Word16 where@@ -183,6 +194,7 @@   zero = 0  instance Subtractive Word16 where+  (-) = (P.-)   negate = P.negate  instance Additive Word32 where@@ -190,6 +202,7 @@   zero = 0  instance Subtractive Word32 where+  (-) = (P.-)   negate = P.negate  instance Additive Word64 where@@ -197,6 +210,7 @@   zero = 0  instance Subtractive Word64 where+  (-) = (P.-)   negate = P.negate  instance (Additive b) => Additive (a -> b) where@@ -204,4 +218,5 @@   zero _ = zero  instance (Subtractive b) => Subtractive (a -> b) where+  f - f' = \a -> f a - f' a   negate f = negate P.. f
src/NumHask/Algebra/Field.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE TypeFamilies #-} --- | Field classes+-- | [field](https://en.wikipedia.org/wiki/Field_(mathematics\)) classes module NumHask.Algebra.Field   ( SemiField,     Field,@@ -12,6 +12,9 @@     nan,     TrigField (..),     half,+    modF,+    divF,+    divModF,   ) where @@ -24,8 +27,8 @@     (/),   ) import NumHask.Algebra.Ring (Distributive, Ring, two)-import NumHask.Data.Integral (Integral, even)-import Prelude ((.))+import NumHask.Data.Integral (FromIntegral (..), Integral, even)+import Prelude (Eq (..), (.)) import Prelude qualified as P  -- $setup@@ -35,7 +38,7 @@ -- >>> :set -XScopedTypeVariables -- >>> import NumHask.Prelude --- | A <https://en.wikipedia.org/wiki/Semifield Semifield> is a field with no substraction.+-- | A <https://en.wikipedia.org/wiki/Semifield Semifield> is a field with no subtraction. -- -- @since 0.12 type SemiField a = (Distributive a, Divisive a)@@ -239,7 +242,7 @@   atan2 = P.atan2   sinh = P.sinh   cosh = P.cosh-  asinh = P.sinh+  asinh = P.asinh   acosh = P.acosh   atanh = P.atanh @@ -253,7 +256,7 @@   atan2 = P.atan2   sinh = P.sinh   cosh = P.cosh-  asinh = P.sinh+  asinh = P.asinh   acosh = P.acosh   atanh = P.atanh @@ -277,3 +280,43 @@ -- 0.5 half :: (Additive a, Divisive a) => a half = one / two++-- | Approximate modulo for fields+--+-- @since 0.13+--+-- >>> modF 1.5 1.2+-- 0.30000000000000004+modF :: (Eq a, Field a, FromIntegral a (Whole a), QuotientField a) => a -> a -> a+modF n d+  | d == infinity = n+  | d == zero = nan+  | P.True = n - d * fromIntegral (floor (n / d))++-- | Approximate diviso for fields.+--+-- Compared with 'NumHask.Algebra.Field.div', divF returns the original type rather than the 'Whole' type.+--+-- @since 0.13+--+-- >>> divF 1.5 1.2+-- 1.0+divF :: (Eq a, Field a, FromIntegral a (Whole a), QuotientField a) => a -> a -> a+divF n d+  | d == infinity = zero+  | d == zero = infinity+  | P.True = fromIntegral (floor (n / d))++-- | Approximate `NumHask.Algebra.Field.divMod` for fields.+--+-- @since 0.13+--+-- >>> divModF 1.5 1.2+-- (1.0,0.30000000000000004)+divModF :: (Eq a, Field a, FromIntegral a (Whole a), QuotientField a) => a -> a -> (a, a)+divModF n d+  | d == infinity = (zero, n)+  | d == zero = (infinity, nan)+  | P.True = (div', n - d * div')+  where+    div' = fromIntegral (floor (n / d))
src/NumHask/Algebra/Group.hs view
@@ -40,6 +40,12 @@ instance (Magma b) => Magma (a -> b) where   f ⊕ g = \a -> f a ⊕ g a +instance Magma Bool where+  a ⊕ b = a || b++instance Unital Bool where+  unit = False+ -- | A Unital Magma is a magma with an --   <https://en.wikipedia.org/wiki/Identity_element identity element> (the --   unit).@@ -115,6 +121,8 @@   Idempotent a  instance (Idempotent b) => Idempotent (a -> b)++instance Idempotent Bool  -- | An <https://en.wikipedia.org/wiki/Abelian_group Abelian Group> is an --   Associative, Unital, Invertible and Commutative Magma . In other words, it
src/NumHask/Algebra/Lattice.hs view
@@ -6,8 +6,8 @@     MeetSemiLattice (..),     meetLeq,     (</),-    BoundedJoinSemiLattice (..),-    BoundedMeetSemiLattice (..),+    LowerBounded (..),+    UpperBounded (..),     Lattice,     BoundedLattice,   )@@ -76,45 +76,45 @@  -- | A join-semilattice with an identity element 'bottom' for '\/'. ----- > x \/ bottom == bottom-class (JoinSemiLattice a) => BoundedJoinSemiLattice a where+-- > x \/ bottom == x+class (JoinSemiLattice a) => LowerBounded a where   bottom :: a  -- | A meet-semilattice with an identity element 'top' for '/\'. ----- > x /\ top == top-class (MeetSemiLattice a) => BoundedMeetSemiLattice a where+-- > x /\ top == x+class (MeetSemiLattice a) => UpperBounded a where   top :: a  -- | Lattices with both bounds ----- > x /\ bottom == x--- > x \/ top = x-type BoundedLattice a = (JoinSemiLattice a, MeetSemiLattice a, BoundedJoinSemiLattice a, BoundedMeetSemiLattice a)+-- > x /\ bottom == bottom+-- > x \/ top == top+type BoundedLattice a = (JoinSemiLattice a, MeetSemiLattice a, LowerBounded a, UpperBounded a)  instance JoinSemiLattice Float where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Float where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Double where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Double where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Int where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Int where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Integer where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Integer where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Bool where   (\/) = (||)@@ -123,142 +123,142 @@   (/\) = (&&)  instance JoinSemiLattice Natural where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Natural where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Int8 where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Int8 where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Int16 where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Int16 where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Int32 where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Int32 where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Int64 where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Int64 where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Word where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Word where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Word8 where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Word8 where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Word16 where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Word16 where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Word32 where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Word32 where-  (/\) = max+  (/\) = min  instance JoinSemiLattice Word64 where-  (\/) = min+  (\/) = max  instance MeetSemiLattice Word64 where-  (/\) = max+  (/\) = min -instance BoundedJoinSemiLattice Float where+instance LowerBounded Float where   bottom = negInfinity -instance BoundedMeetSemiLattice Float where+instance UpperBounded Float where   top = infinity -instance BoundedJoinSemiLattice Double where+instance LowerBounded Double where   bottom = negInfinity -instance BoundedMeetSemiLattice Double where+instance UpperBounded Double where   top = infinity -instance BoundedJoinSemiLattice Int where+instance LowerBounded Int where   bottom = minBound -instance BoundedMeetSemiLattice Int where+instance UpperBounded Int where   top = maxBound -instance BoundedJoinSemiLattice Bool where+instance LowerBounded Bool where   bottom = False -instance BoundedMeetSemiLattice Bool where+instance UpperBounded Bool where   top = True -instance BoundedJoinSemiLattice Natural where+instance LowerBounded Natural where   bottom = zero -instance BoundedJoinSemiLattice Int8 where+instance LowerBounded Int8 where   bottom = minBound -instance BoundedMeetSemiLattice Int8 where+instance UpperBounded Int8 where   top = maxBound -instance BoundedJoinSemiLattice Int16 where+instance LowerBounded Int16 where   bottom = minBound -instance BoundedMeetSemiLattice Int16 where+instance UpperBounded Int16 where   top = maxBound -instance BoundedJoinSemiLattice Int32 where+instance LowerBounded Int32 where   bottom = minBound -instance BoundedMeetSemiLattice Int32 where+instance UpperBounded Int32 where   top = maxBound -instance BoundedJoinSemiLattice Int64 where+instance LowerBounded Int64 where   bottom = minBound -instance BoundedMeetSemiLattice Int64 where+instance UpperBounded Int64 where   top = maxBound -instance BoundedJoinSemiLattice Word where+instance LowerBounded Word where   bottom = minBound -instance BoundedMeetSemiLattice Word where+instance UpperBounded Word where   top = maxBound -instance BoundedJoinSemiLattice Word8 where+instance LowerBounded Word8 where   bottom = minBound -instance BoundedMeetSemiLattice Word8 where+instance UpperBounded Word8 where   top = maxBound -instance BoundedJoinSemiLattice Word16 where+instance LowerBounded Word16 where   bottom = minBound -instance BoundedMeetSemiLattice Word16 where+instance UpperBounded Word16 where   top = maxBound -instance BoundedJoinSemiLattice Word32 where+instance LowerBounded Word32 where   bottom = minBound -instance BoundedMeetSemiLattice Word32 where+instance UpperBounded Word32 where   top = maxBound -instance BoundedJoinSemiLattice Word64 where+instance LowerBounded Word64 where   bottom = minBound -instance BoundedMeetSemiLattice Word64 where+instance UpperBounded Word64 where   top = maxBound
src/NumHask/Algebra/Metric.hs view
@@ -1,9 +1,6 @@-{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -Wno-name-shadowing #-}-{-# OPTIONS_GHC -Wno-type-equality-out-of-scope #-}  -- | Metric classes module NumHask.Algebra.Metric@@ -28,8 +25,10 @@  import Control.Applicative import Data.Bool+import Data.Data import Data.Int (Int16, Int32, Int64, Int8) import Data.Kind+import Data.Type.Equality import Data.Word (Word16, Word32, Word64, Word8) import GHC.Generics import GHC.Natural (Natural (..))@@ -39,7 +38,7 @@ import NumHask.Algebra.Lattice import NumHask.Algebra.Multiplicative import NumHask.Algebra.Ring-import Prelude (Double, Eq (..), Float, Functor (..), Int, Integer, Ord, Show, Word, fromRational)+import Prelude (Double, Eq (..), Float, Functor (..), Int, Integer, Read, Show, Word, fromRational) import Prelude qualified as P  -- $setup@@ -222,7 +221,7 @@ -- -- See [Polar coordinate system](https://en.wikipedia.org/wiki/Polar_coordinate_system) data Polar a = Polar {radial :: a, azimuth :: a}-  deriving (Generic, Show, Eq)+  deriving (Eq, Show, Read, Generic, Data)  instance (Additive a, Multiplicative a) => Basis (Polar a) where   type Mag (Polar a) = a@@ -258,7 +257,7 @@ -- >>> nearZero (epsilon :: EuclideanPair Double) -- True nearZero :: (Epsilon a, Lattice a, Subtractive a) => a -> Bool-nearZero a = epsilon /\ a == epsilon && epsilon /\ negate a == epsilon+nearZero a = a /\ epsilon == a && negate a /\ epsilon == negate a  -- | Approximate equality --@@ -312,10 +311,7 @@ -- @since 0.11 newtype EuclideanPair a = EuclideanPair {euclidPair :: (a, a)}   deriving stock-    ( Generic,-      Eq,-      Show-    )+    (Eq, Show, Generic, Data)  instance Functor EuclideanPair where   fmap f (EuclideanPair (x, y)) = EuclideanPair (f x, f y)@@ -330,6 +326,7 @@   zero = pure zero  instance (Subtractive a) => Subtractive (EuclideanPair a) where+  (-) = liftA2 (-)   negate = fmap negate  instance@@ -340,7 +337,7 @@   one = pure one  instance-  (Subtractive a, Divisive a) =>+  (Divisive a) =>   Divisive (EuclideanPair a)   where   recip = fmap recip@@ -372,10 +369,10 @@ instance (MeetSemiLattice a) => MeetSemiLattice (EuclideanPair a) where   (/\) (EuclideanPair (x, y)) (EuclideanPair (x', y')) = EuclideanPair (x /\ x', y /\ y') -instance (BoundedJoinSemiLattice a) => BoundedJoinSemiLattice (EuclideanPair a) where+instance (LowerBounded a) => LowerBounded (EuclideanPair a) where   bottom = pure bottom -instance (BoundedMeetSemiLattice a) => BoundedMeetSemiLattice (EuclideanPair a) where+instance (UpperBounded a) => UpperBounded (EuclideanPair a) where   top = pure top  instance (Multiplicative a) => MultiplicativeAction (EuclideanPair a) where@@ -385,21 +382,11 @@ instance (Divisive a) => DivisiveAction (EuclideanPair a) where   (|/) e s = fmap (/ s) e -instance (Ord a, TrigField a, ExpField a) => ExpField (EuclideanPair a) where+instance (TrigField a, ExpField a) => ExpField (EuclideanPair a) where   exp (EuclideanPair (x, y)) = EuclideanPair (exp x * cos y, exp x * sin y)-  log (EuclideanPair (x, y)) = EuclideanPair (log (sqrt (x * x + y * y)), atan2' y x)-    where-      atan2' y x-        | x P.> zero = atan (y / x)-        | x P.== zero P.&& y P.> zero = pi / (one + one)-        | x P.< one P.&& y P.> one = pi + atan (y / x)-        | (x P.<= zero P.&& y P.< zero) || (x P.< zero) =-            negate (atan2' (negate y) x)-        | y P.== zero = pi -- must be after the previous test on zero y-        | x P.== zero P.&& y P.== zero = y -- must be after the other double zero tests-        | P.otherwise = x + y -- x or y is a NaN, return a NaN (via +)+  log (EuclideanPair (x, y)) = EuclideanPair (log (sqrt (x * x + y * y)), atan2 y x) -instance (QuotientField a, Subtractive a) => QuotientField (EuclideanPair a) where+instance (QuotientField a) => QuotientField (EuclideanPair a) where   type Whole (EuclideanPair a) = EuclideanPair (Whole a)    properFraction (EuclideanPair (x, y)) =
+ src/NumHask/Algebra/Patterns.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ViewPatterns #-}++-- | Patterns for common tests+module NumHask.Algebra.Patterns+  ( pattern Zero,+    pattern One,+    pattern MinusOne,+  )+where++import NumHask.Algebra.Additive+import NumHask.Algebra.Multiplicative+import Prelude (Bool (..), Eq (..), (.))++-- | Enabling pattern matching on zero:+--+-- > isItZero Zero = True+-- > isItZero _    = False+pattern Zero :: forall a. (Eq a, Additive a) => a+pattern Zero <- ((== zero) -> True)++-- | Enabling pattern matching on one:+--+-- > isItOne One = True+-- > isItOne _   = False+pattern One :: forall a. (Eq a, Multiplicative a) => a+pattern One <- ((== one) -> True)++-- | Enabling pattern matching on minus one:+--+-- > isItMinusOne MinusOne = True+-- > isItMinusOne _        = False+--+-- The means of testing (that is, add one, and check if it equals+-- zero) might be surprising. Other, more obvious, methods would+-- result in underflow errors. (For example, we could negate and test+-- if it's equal to one, but that would fail on any nonzero+-- 'Natural'. Similarly, we could test for equality with the negation of+-- one, but that would fail on any 'Natural' whatsoever, since 'negate+-- one' underflows.)+pattern MinusOne :: forall a. (Eq a, Additive a, Multiplicative a) => a+pattern MinusOne <- ((== zero) . (+ one) -> True)
src/NumHask/Algebra/Ring.hs view
@@ -52,9 +52,13 @@ -- > \a -> a * zero == zero type Ring a = (Distributive a, Subtractive a) --- | A <https://en.wikipedia.org/wiki/Semiring#Star_semirings StarSemiring> is a semiring with an additional unary operator (star) satisfying:+-- | A <https://en.wikipedia.org/wiki/Semiring#Star_semirings StarSemiring> is a semiring with a unary star operator satisfying the Conway equations: ----- > \a -> star a == one + a * star a+-- > \a -> star a == one + a * star a                                  -- fixpoint+-- > \a b -> star (a * b) == one + a * star (b * a) * b                -- product-star (sliding)+-- > \a b -> star (a + b) == star (star a * b) * star a                -- sum-star (vanishing)+--+-- These three equations are the doctestable core; they are exactly the sliding and vanishing axioms of a traced category in semiring clothing. class (Distributive a) => StarSemiring a where   {-# MINIMAL star | plus #-} @@ -66,9 +70,26 @@  -- | A <https://en.wikipedia.org/wiki/Kleene_algebra Kleene Algebra> is a Star Semiring with idempotent addition. ----- > a * x + x = a ==> star a * x + x = x--- > x * a + x = a ==> x * star a + x = x+-- Idempotent addition gives a natural order @a <= b ⟺ a + b == b@. In that order, Kozen's induction laws hold as derived facts:+--+-- > a * x + x <= x  ==>  star a * x + x <= x+-- > x * a + x <= x  ==>  x * star a + x <= x+--+-- They are stated here as prose rather than class laws because they involve a partial order and Horn clauses, which do not fit the equational/doctest style of the Conway core. class (StarSemiring a, Idempotent a) => KleeneAlgebra a++instance StarSemiring P.Bool where+  star _ = P.True++instance KleeneAlgebra P.Bool++-- | Conway equations for 'Bool'.+--+-- >>> let a = False; b = True in star (a * b) == one + a * star (b * a) * b+-- True+--+-- >>> let a = False; b = True in star (a + b) == star (star a * b) * star a+-- True  -- | Involutive Ring --
+ src/NumHask/Algebra/Tropical.hs view
@@ -0,0 +1,65 @@+-- | Tropical semirings.+module NumHask.Algebra.Tropical+  ( MinPlus (..),+  )+where++import NumHask.Algebra.Additive (Additive (..))+import NumHask.Algebra.Group (Idempotent, Magma (..))+import NumHask.Algebra.Multiplicative (Multiplicative (..))+import NumHask.Algebra.Ring (KleeneAlgebra, StarSemiring (..))+import Prelude (Double, Eq, Ord, Show, fromInteger)+import Prelude qualified as P++-- $setup+--+-- >>> :m -Prelude+-- >>> :set -XRebindableSyntax+-- >>> import NumHask.Prelude+-- >>> import NumHask.Algebra.Tropical++-- | The min-plus tropical semiring.+--+-- Addition is 'min', multiplication is ordinary addition, the additive unit+-- is positive infinity, and the multiplicative unit is zero.+--+-- >>> MinPlus 3 + MinPlus 2 :: MinPlus Double+-- MinPlus {getMinPlus = 2.0}+--+-- >>> MinPlus 3 * MinPlus 2 :: MinPlus Double+-- MinPlus {getMinPlus = 5.0}+newtype MinPlus a = MinPlus+  { getMinPlus :: a+  }+  deriving (Eq, Ord, Show)++instance Additive (MinPlus Double) where+  MinPlus a + MinPlus b = MinPlus (P.min a b)+  zero = MinPlus (1 P./ 0)++instance Multiplicative (MinPlus Double) where+  MinPlus a * MinPlus b = MinPlus (a P.+ b)+  one = MinPlus 0++instance Magma (MinPlus Double) where+  a ⊕ b = a + b++instance Idempotent (MinPlus Double)++-- | Star is zero in a min-plus semiring: the cheapest repeated traversal is+-- to stay put.+--+-- >>> star (MinPlus 2 :: MinPlus Double)+-- MinPlus {getMinPlus = 0.0}+--+-- Conway equations for 'MinPlus Double'.+--+-- >>> let a = MinPlus 2 :: MinPlus Double; b = MinPlus 3 :: MinPlus Double in star (a * b) == one + a * star (b * a) * b+-- True+--+-- >>> let a = MinPlus 2 :: MinPlus Double; b = MinPlus 3 :: MinPlus Double in star (a + b) == star (star a * b) * star a+-- True+instance StarSemiring (MinPlus Double) where+  star _ = one++instance KleeneAlgebra (MinPlus Double)
src/NumHask/Data/Complex.hs view
@@ -8,6 +8,7 @@     (+:),     realPart,     imagPart,+    normSquared,   ) where @@ -41,14 +42,19 @@     (/),   ) +-- $setup+--+-- >>> import NumHask.Prelude+-- >>> :m -Prelude+ -- | The underlying representation is a newtype-wrapped tuple, compared with the base datatype. This was chosen to facilitate the use of DerivingVia. newtype Complex a = Complex {complexPair :: (a, a)}   deriving stock     ( Eq,       Show,       Read,-      Data,       Generic,+      Data,       Functor     )   deriving@@ -59,8 +65,8 @@       Epsilon,       JoinSemiLattice,       MeetSemiLattice,-      BoundedJoinSemiLattice,-      BoundedMeetSemiLattice,+      LowerBounded,+      UpperBounded,       ExpField     )     via (EuclideanPair a)@@ -68,6 +74,14 @@ infixl 6 +:  -- | Complex number constructor.+--+-- Internally, Complex derives most instances via EuclideanPair. For instance,+--+-- >>> sqrt (1.0 +: (-1.0)) :: Complex Double+-- Complex {complexPair = (1.0986841134678098,-0.45508986056222733)}+--+-- >>> sqrt ((-1.0) +: 0.0) :: Complex Double+-- Complex {complexPair = (6.123233995736766e-17,1.0)} (+:) :: a -> a -> Complex a (+:) r i = Complex (r, i) @@ -118,3 +132,8 @@   ceiling (Complex (x, y)) = Complex (ceiling x, ceiling y)   floor (Complex (x, y)) = Complex (floor x, floor y)   truncate (Complex (x, y)) = Complex (truncate x, truncate y)++-- | The squared norm: frequently useful, and doesn't require the+-- ability to take square roots.+normSquared :: (Distributive a) => Complex a -> a+normSquared (Complex (x, y)) = x * x + y * y
src/NumHask/Data/Integral.hs view
@@ -10,6 +10,7 @@     odd,     (^^),     (^),+    (^+),   ) where @@ -116,6 +117,18 @@   rem f f' a = f a `mod` f' a   quotRem f f' = (\a -> fst (f a `quotRem` f' a), \a -> snd (f a `quotRem` f' a)) +-- |+-- >>> even 2+-- True+even :: (P.Eq a, Integral a) => a -> P.Bool+even n = n `rem` (one + one) P.== zero++-- |+-- >>> odd 3+-- True+odd :: (P.Eq a, Integral a) => a -> P.Bool+odd = P.not . even+ -- | toIntegral is kept separate from Integral to help with compatability issues. -- -- > toIntegral a == a@@ -409,17 +422,9 @@ instance FromInteger Word64 where   fromInteger = P.fromInteger --- |--- >>> even 2--- True-even :: (P.Eq a, Integral a) => a -> P.Bool-even n = n `rem` (one + one) P.== zero+deriving instance (FromInteger a) => FromInteger (Sum a) --- |--- >>> odd 3--- True-odd :: (P.Eq a, Integral a) => a -> P.Bool-odd = P.not . even+deriving instance (FromInteger a) => FromInteger (Product a)  infixr 8 ^^ @@ -464,3 +469,32 @@ (^) ::   (Divisive a) => a -> Int -> a (^) x n = x ^^ n++infixr 8 ^+++-- | raise a number to a non-negative 'Natural' power.+--+-- Unlike '(^^)' and '(^)', this does not require 'Divisive' or 'Subtractive'+-- constraints, so it works for unsigned types such as 'Natural' and 'Word64'.+--+-- >>> 2 ^+ 3+-- 8+--+-- >>> 2 ^+ 0+-- 1+(^+) ::+  (Multiplicative a) => a -> Natural -> a+x0 ^+ y0 =+  case compare y0 zero of+    EQ -> one+    GT -> f x0 y0+    LT -> P.error "(^+): negative exponent"+  where+    f x y+      | even y = f (x * x) (y `quot` two)+      | y P.== one = x+      | P.otherwise = g (x * x) (y `quot` two) x+    g x y z+      | even y = g (x * x) (y `quot` two) z+      | y P.== one = x * z+      | P.otherwise = g (x * x) (y `quot` two) (x * z)
src/NumHask/Data/Positive.hs view
@@ -28,6 +28,7 @@ import NumHask.Data.Integral import NumHask.Data.Rational import NumHask.Data.Wrapped+import Numeric.Natural (Natural, minusNaturalMaybe) import Prelude (Eq, Ord, Show) import Prelude qualified as P @@ -84,11 +85,11 @@       DivisiveAction,       JoinSemiLattice,       MeetSemiLattice,-      BoundedMeetSemiLattice+      UpperBounded     )     via (Wrapped a) -instance (MeetSemiLattice a, Integral a) => FromIntegral (Positive a) a where+instance (JoinSemiLattice a, Integral a) => FromIntegral (Positive a) a where   fromIntegral a = positive a  instance (FromIntegral a b) => FromIntegral (Positive a) b where@@ -103,7 +104,7 @@ instance (ToRatio a b) => ToRatio (Positive a) b where   toRatio (UnsafePositive a) = toRatio a -instance (Additive a, JoinSemiLattice a) => BoundedJoinSemiLattice (Positive a) where+instance (Additive a, JoinSemiLattice a) => LowerBounded (Positive a) where   bottom = UnsafePositive zero  instance QuotientField (Positive P.Double) where@@ -124,8 +125,8 @@ -- -- >>> positive (-1) -- UnsafePositive {unPositive = 0}-positive :: (Additive a, MeetSemiLattice a) => a -> Positive a-positive a = UnsafePositive (a /\ zero)+positive :: (Additive a, JoinSemiLattice a) => a -> Positive a+positive a = UnsafePositive (a \/ zero)  -- | Unsafe constructor. --@@ -139,9 +140,9 @@ -- >>> maybePositive (-one) -- Nothing maybePositive :: (Additive a, MeetSemiLattice a) => a -> Maybe (Positive a)-maybePositive a = bool Nothing (Just (UnsafePositive a)) (a `meetLeq` zero)+maybePositive a = bool Nothing (Just (UnsafePositive a)) (zero `meetLeq` a) -instance (Subtractive a, MeetSemiLattice a) => Monus (Positive a) where+instance (Subtractive a, JoinSemiLattice a) => Monus (Positive a) where   (UnsafePositive a) ∸ (UnsafePositive b) = positive (a - b)  -- | A field but with truncated subtraction.@@ -161,9 +162,26 @@    infixl 6 ∸   (∸) :: a -> a -> a-  default (∸) :: (BoundedJoinSemiLattice a, MeetSemiLattice a, Subtractive a) => a -> a -> a-  a ∸ b = bottom /\ (a - b)+  default (∸) :: (LowerBounded a, Subtractive a) => a -> a -> a+  a ∸ b = bottom \/ (a - b) +-- | A newtype wrapper intended for defining Monus instances by:+-- "x ∸ y = if x < y then zero else x - y"+newtype MonusFromOrd a = MonusFromOrd a+  deriving (Eq, Ord, Additive, Subtractive)++instance (Ord a, Subtractive a) => Monus (MonusFromOrd a) where+  x ∸ y+    | x P.< y = zero+    | P.otherwise = x - y++-- | It appears that Haskell doesn't have any built in truncated+-- subtraction operation for Word+deriving via MonusFromOrd P.Word instance Monus P.Word++instance Monus Natural where+  x ∸ y = fromMaybe 0 (minusNaturalMaybe x y)+ -- | Truncated addition -- -- @since 0.12@@ -171,5 +189,5 @@   {-# MINIMAL (∔) #-}   infixl 6 ∔   (∔) :: a -> a -> a-  default (∔) :: (BoundedMeetSemiLattice a, JoinSemiLattice a, Additive a) => a -> a -> a+  default (∔) :: (UpperBounded a, JoinSemiLattice a, Additive a) => a -> a -> a   a ∔ b = top \/ (a + b)
src/NumHask/Data/Rational.hs view
@@ -10,6 +10,8 @@     FromRational (..),     reduce,     gcd,+    numerator,+    denominator,   ) where @@ -41,7 +43,13 @@ -- | Ratio of two integers type Rational = Ratio Integer -instance (P.Eq a, Subtractive a, EndoBased a, Absolute a, Integral a) => P.Eq (Ratio a) where+numerator :: Ratio a -> a+numerator (a :% _) = a++denominator :: Ratio a -> a+denominator (_ :% a) = a++instance (P.Eq a, P.Ord a, Subtractive a, EndoBased a, Absolute a, Integral a) => P.Eq (Ratio a) where   a@(xa :% ya) == b@(xb :% yb)     | isRNaN a P.|| isRNaN b = P.False     | xa == zero P.&& xb == zero = P.True@@ -82,7 +90,7 @@   Divisive (Ratio a)   where   recip (x :% y)-    | signum x P.== negate one = negate y :% negate x+    | x P.< zero = negate y :% negate x     | P.otherwise = y :% x  instance (P.Ord a, EndoBased a, Absolute a, ToInt a, Integral a, Ring a) => QuotientField (Ratio a) where@@ -100,13 +108,16 @@   magnitude (n :% d) = abs n :% abs d  instance (P.Ord a, Integral a, EndoBased a, Subtractive a) => JoinSemiLattice (Ratio a) where-  (\/) = P.min+  (\/) = P.max  instance (P.Ord a, Integral a, EndoBased a, Subtractive a) => MeetSemiLattice (Ratio a) where-  (/\) = P.max+  (/\) = P.min -instance (P.Ord a, EndoBased a, Integral a, Ring a, MeetSemiLattice a) => Epsilon (Ratio a)+instance (P.Ord a, EndoBased a, Integral a, Ring a) => Epsilon (Ratio a) +instance (FromInteger a, Multiplicative a) => FromInteger (Ratio a) where+  fromInteger x = fromInteger x :% one+ instance (FromIntegral a b, Multiplicative a) => FromIntegral (Ratio a) b where   fromIntegral x = fromIntegral x :% one @@ -208,7 +219,7 @@ -- -- prop> \a b -> reduce a b == a :% b || b == zero reduce ::-  (P.Eq a, Subtractive a, EndoBased a, Integral a) => a -> a -> Ratio a+  (P.Ord a, Subtractive a, EndoBased a, Integral a) => a -> a -> Ratio a reduce x y   | x P.== zero P.&& y P.== zero = zero :% zero   | z P.== zero = one :% zero@@ -216,7 +227,7 @@   where     z = gcd x y     n % d-      | signum d P.== negate one = negate n :% negate d+      | d P.< zero = negate n :% negate d       | P.otherwise = n :% d  -- | @'gcd' x y@ is the non-negative factor of both @x@ and @y@ of which
src/NumHask/Data/Wrapped.hs view
@@ -37,8 +37,8 @@       FromRational,       MeetSemiLattice,       JoinSemiLattice,-      BoundedJoinSemiLattice,-      BoundedMeetSemiLattice,+      LowerBounded,+      UpperBounded,       Basis,       Direction,       Epsilon,
src/NumHask/Exception.hs view
@@ -6,11 +6,10 @@ where  import Control.Exception-import Data.Typeable (Typeable) import Prelude qualified as P  -- | A numhask exception. newtype NumHaskException = NumHaskException {errorMessage :: P.String}-  deriving (P.Show, Typeable)+  deriving (P.Show)  instance Exception NumHaskException
− test/doctests.hs
@@ -1,8 +0,0 @@-module Main where--import System.Environment (getArgs)-import Test.DocTest (mainFromCabal)-import Prelude (IO, (=<<))--main :: IO ()-main = mainFromCabal "numhask" =<< getArgs