Skip to content

Commit

Permalink
readme and haddock fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyday567 committed Feb 12, 2024
1 parent a4e7d4e commit 9a2a77d
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 7 deletions.
9 changes: 7 additions & 2 deletions numhask.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 3.0
name: numhask
version: 0.12.0.0
version: 0.12.0.1
license: BSD-3-Clause
license-file: LICENSE
copyright: Tony Day (c) 2016
Expand All @@ -15,7 +15,7 @@ description:

The numeric class constellation looks somewhat like:

![nh](docs/other/nh.svg)
![nh](docs/other/nh12.svg)

== Usage

Expand Down Expand Up @@ -49,9 +49,14 @@ common ghc-options-stanza
common ghc2021-stanza
default-language: GHC2021

common docspec
x-docspec-extra-packages: QuickCheck
build-depends: QuickCheck

library
import: ghc-options-stanza
import: ghc2021-stanza
import: docspec
hs-source-dirs: src
build-depends:
, base >=4.7 && <5
Expand Down
File renamed without changes
32 changes: 32 additions & 0 deletions other/nh12.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
114 changes: 114 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,120 @@ numhask
[![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)

![](other/nh12.svg)


SemiField
---

Compared to previous library versions, Ring and Field have been removed as super classes of QuotientField, and SemiField introduced as the new constraint.

Old version:

![](other/nh11.svg)

```
type SemiField a = (Distributive a, Divisive a)
class (SemiField a) => QuotientField a where
type Whole a :: Type
properFraction :: a -> (Whole a, a)
```

The notion of a quotient is now that which distributes and divides.

Subtractive originally slipped in as a super class due to the notion of rounding down (or, specifically, towards zero). By using DefaultSignatures, a default for Subtractive-type numbers can be provided and still allow non-Subtractive (SemiField) things to be quotient fields.

Infinity and nan move from a Field to a SemiField constraint - subtraction is not needed to come up with an infinity or silly compute.

Positive
---

A motivation for SemiField was to introduce NumHask.Data.Positive into the library. Positive has no sane Subtractive instance (but should be able to be rounded).

Out of the many approaches that can be taken in defining a positive number, the definition relies on a notion of truncated subtraction; that subtraction can be performed on positive numbers but, for answers outside the typed range, the lower bound should be returned.

Specifically, the positive constructor needs to be supplied with a number that has a MeetSemiLattice instance, so that complex numbers and other geometries are correctly handled:

``` haskell
ghci> 2 +: (-2)
Complex {complexPair = (2,-2)}
ghci> positive (2 +: (-2))
UnsafePositive {unPositive = Complex {complexPair = (2,0)}}
```

Truncated Arithmetic
---

Truncated subtraction can be generalised to a notion of truncated arithmetic on a number with a typed range. This may be a direction explored further in the library including:

- [epsilon, +infinity): A positive number type which is a safe divisor.
- /= zero, non-zero arithmetic (x - x returns epsilon, say)
- [0,1]: probability and weight arithmetic
- [-1,1]: correlation math

magnitudes are positive
---

The current Basis instance of Double:

``` haskell
instance Basis Double where
type Mag Double = Double
type Base Double = Double
magnitude = P.abs
basis = P.signum
```

is probably more correctly written as:

``` haskell
instance Basis Double where
type Mag Double = Positive Double
type Base Double = Sign Double
magnitude = Positive . P.abs
basis = Sign . P.signum
```

where Sign is a future-imagined type representing {-1,0,1} or {-1,1}

In Haskell, there is a basic choice between using multiple parameters for a type or embedding types using type families. Using multiple parameters would, in practice, force users to have to chose and write 'Basis Double Double Double' or 'Basis Positive Sign Double'.

On balance, a computational chain involving magnitude is likely to be a single, underlying type, so that providing a Basis instance returning a Positive would result in a lot of unwrapping.

``` haskell
-- endo-based
x == basis x * magnitude x

-- if hetero-typed ...
x == (unSign $ basis x) * (unPositive $ magnitude x)
```

The library awaits real-world feedback on safety versus ergonomics.

Monus
---

Truncated subtraction is encapsulated within the Monus class and supplied operator:

``` haskell
ghci> 4 7 :: Positive Int
UnsafePositive {unPositive = 0}
ghci> unPositive (4 7 :: Positive Int)
0
ghci> unPositive (7 4 :: Positive Int)
3
```





- introduced NumHask.Data.Positive

- introduced NumHask.Data.Wrapped


This package provides numeric classes alternate to the prelude as specified in haskell98.

The numeric class constellation looks somewhat like:
Expand Down
26 changes: 21 additions & 5 deletions src/NumHask/Data/Positive.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

-- | Field classes
-- | A positive number type, defined as existing on [zero, +infinity)
module NumHask.Data.Positive
( Positive (..),
positive,
Expand Down Expand Up @@ -37,19 +37,34 @@ import Prelude qualified as P
-- >>> import NumHask.Prelude
-- >>> import NumHask.Data.Positive

-- | zero is positive
-- | A positive number is a number that is contained in [zero,+infinity).
--
-- >>> 1 :: Positive Int
-- UnsafePositive {unPositive = 1}
--
--
-- >>> -1 :: Positive Int
-- ...
-- • No instance for ‘Subtractive (Positive Int)’
-- arising from a use of syntactic negation
-- ...
--
-- zero is positive
--
-- >>> positive 0 == zero
-- True
--
-- The main constructors:
--
-- >>> positive (-1)
-- UnsafePositive {unPositive = 0}
--
-- >>> maybePositive (-1)
-- Nothing
--
-- >>> UnsafePositive (-1)
-- UnsafePositive {unPositive = -1}
--
newtype Positive a = UnsafePositive {unPositive :: a}
deriving stock
(Eq, Ord, Show)
Expand Down Expand Up @@ -105,21 +120,22 @@ instance QuotientField (Positive P.Double) where
P.EQ -> bool (n + one) n (even n)
P.GT -> n + one

-- | Constructor which returns zero for a negative input.
-- | Constructor which returns zero for a negative number.
--
-- >>> positive (-1)
-- UnsafePositive {unPositive = 0}
positive :: (Additive a, MeetSemiLattice a) => a -> Positive a
positive a = UnsafePositive (a /\ zero)

-- | Unsafe constructors.
-- | Unsafe constructor.
--
-- >>> positive_ (-one)
-- UnsafePositive {unPositive = -1}
positive_ :: a -> Positive a
positive_ = UnsafePositive

-- | Constructor which returns Nothing for a negative number.
-- | Constructor which returns Nothing if a negative number is supplied.
--
-- >>> maybePositive (-one)
-- Nothing
maybePositive :: (Additive a, MeetSemiLattice a) => a -> Maybe (Positive a)
Expand Down

0 comments on commit 9a2a77d

Please sign in to comment.