{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
module Natural (
Natural
, HasNatural(..)
, AsNatural(..)
, ProductNatural(..)
, MaxNatural(..)
, MinNatural(..)
, zero
, zero'
, successor
, successor'
, plus
, multiply
, square
, zeroOr
, length
, replicate
, take
, drop
, splitAt
, (!!)
, findIndices
, findIndex
, elemIndices
, elemIndex
, minus
, list
, Positive
, HasPositive(..)
, AsPositive(..)
, SumPositive(..)
, MaxPositive(..)
, MinPositive(..)
, naturalPositive
, one
, one'
, successor1
, successor1'
, successorW
, plus1
, multiply1
, square1
, oneOr
, notZero
, length1
, replicate1
, take1
, drop1
, splitAt1
, (!!!)
, findIndices1
, findIndex1
, elemIndices1
, elemIndex1
, minus1
, list1
, plusone
, minusone
) where
import Control.Applicative(Const)
import Control.Category((.), id)
import Control.Lens(Wrapped(_Wrapped', Unwrapped), Rewrapped, Prism', Lens', Iso', (^?), ( # ), (^.), _Wrapped, prism', iso)
import Control.Monad((>>=))
import Data.Bool(Bool)
import Data.Eq(Eq((==)))
import Data.Foldable(Foldable(foldl))
import Data.Function(const)
import Data.Functor.Identity(Identity)
import Data.Int(Int)
import Data.List(iterate, zip, filter, map, repeat)
import Data.List.NonEmpty(NonEmpty((:|)))
import qualified Data.List.NonEmpty as NonEmpty(iterate, zip, filter)
import Data.Maybe(listToMaybe, Maybe(Just, Nothing), fromMaybe)
import Data.Monoid(Monoid(mappend, mempty))
import Data.Ord(Ord((<)), min, max)
import Data.Semigroup(Semigroup((<>)))
import Data.Semigroup.Foldable(Foldable1(foldMap1))
import Data.Tuple(fst, snd)
import Data.Word(Word)
import Prelude(Show, Integral, Integer, (-), (+), (*), (^), fromIntegral)
newtype Natural =
Natural
Integer
deriving (Eq, Ord, Show)
instance Semigroup Natural where
Natural x <> Natural y =
Natural (x + y)
instance Monoid Natural where
mappend =
(<>)
mempty =
Natural 0
class HasNatural a where
natural ::
Lens'
a
Natural
instance HasNatural Natural where
natural =
id
class AsNatural a where
_Natural ::
Prism'
a
Natural
instance AsNatural Natural where
_Natural =
id
integralPrism ::
Integral a =>
Prism'
a
Natural
integralPrism =
prism'
(\(Natural n) -> fromIntegral n)
(\n -> if n < 0 then Nothing else Just (Natural (fromIntegral n)))
instance AsNatural Int where
_Natural =
integralPrism
instance AsNatural Integer where
_Natural =
integralPrism
instance AsNatural Word where
_Natural =
integralPrism
instance Integral a => AsNatural (Const a b) where
_Natural =
integralPrism
instance Integral a => AsNatural (Identity a) where
_Natural =
integralPrism
newtype ProductNatural =
ProductNatural
Natural
deriving (Eq, Ord, Show)
instance HasNatural ProductNatural where
natural =
_Wrapped . natural
instance AsNatural ProductNatural where
_Natural =
_Wrapped . _Natural
instance ProductNatural ~ a =>
Rewrapped ProductNatural a
instance Wrapped ProductNatural where
type Unwrapped ProductNatural = Natural
_Wrapped' =
iso
(\(ProductNatural x) -> x)
ProductNatural
instance Semigroup ProductNatural where
ProductNatural (Natural x) <> ProductNatural (Natural y) =
ProductNatural (Natural (x * y))
instance Monoid ProductNatural where
mappend =
(<>)
mempty =
ProductNatural (Natural 1)
newtype MaxNatural =
MaxNatural
Natural
deriving (Eq, Ord, Show)
instance HasNatural MaxNatural where
natural =
_Wrapped . natural
instance AsNatural MaxNatural where
_Natural =
_Wrapped . _Natural
instance MaxNatural ~ a =>
Rewrapped MaxNatural a
instance Wrapped MaxNatural where
type Unwrapped MaxNatural = Natural
_Wrapped' =
iso
(\(MaxNatural x) -> x)
MaxNatural
instance Semigroup MaxNatural where
MaxNatural (Natural x) <> MaxNatural (Natural y) =
MaxNatural (Natural (x `max` y))
newtype MinNatural =
MinNatural
Natural
deriving (Eq, Ord, Show)
instance HasNatural MinNatural where
natural =
_Wrapped . natural
instance AsNatural MinNatural where
_Natural =
_Wrapped . _Natural
instance MinNatural ~ a =>
Rewrapped MinNatural a
instance Wrapped MinNatural where
type Unwrapped MinNatural = Natural
_Wrapped' =
iso
(\(MinNatural x) -> x)
MinNatural
instance Semigroup MinNatural where
MinNatural (Natural x) <> MinNatural (Natural y) =
MinNatural (Natural (x `min` y))
zero ::
Prism'
Natural
()
zero =
prism'
(\() -> Natural 0)
(\(Natural n) -> if n == 0 then Just () else Nothing)
zero' ::
Natural
zero' =
zero # ()
successor ::
Prism'
Natural
Natural
successor =
prism'
(\(Natural n) -> Natural (n + 1))
(\(Natural n) -> if n == 0 then Nothing else Just (Natural (n - 1)))
successor' ::
Natural
-> Natural
successor' =
(successor #)
plus ::
Natural
-> Natural
-> Natural
plus =
(<>)
multiply ::
Natural
-> Natural
-> Natural
multiply x y =
(_Wrapped # x <> (_Wrapped # y :: ProductNatural)) ^. _Wrapped
square ::
Natural
-> Natural
-> Natural
square (Natural x) (Natural y) =
Natural (x ^ y)
zeroOr ::
AsNatural a =>
a
-> Natural
zeroOr n =
fromMaybe zero' (n ^? _Natural)
length ::
Foldable f =>
f a
-> Natural
length =
foldl (const . successor') zero'
replicate ::
Natural
-> a
-> [a]
replicate n =
take n . repeat
take ::
Natural
-> [a]
-> [a]
take _ [] =
[]
take n (h:t) =
case n ^? successor of
Nothing ->
[]
Just p ->
h : take p t
drop ::
Natural
-> [a]
-> [a]
drop _ [] =
[]
drop n (h:t) =
case n ^? successor of
Nothing ->
h:t
Just p ->
drop p t
splitAt ::
Natural
-> [a]
-> ([a], [a])
splitAt n x =
(take n x, drop n x)
(!!) ::
[a]
-> Natural
-> Maybe a
[] !! _ =
Nothing
(_:t) !! n =
(n ^? successor) >>= (t !!)
findIndices ::
(a -> Bool)
-> [a]
-> [Natural]
findIndices p x =
map snd (filter (p . fst) (zip x (iterate successor' zero')))
findIndex ::
(a -> Bool)
-> [a]
-> Maybe Natural
findIndex p =
listToMaybe . findIndices p
elemIndices ::
Eq a =>
a
-> [a]
-> [Natural]
elemIndices =
findIndices . (==)
elemIndex ::
Eq a =>
a
-> [a]
-> Maybe Natural
elemIndex =
findIndex . (==)
minus ::
Natural
-> Natural
-> Natural
minus (Natural x) (Natural y) =
Natural (if x < y then 0 else x - y)
list ::
Iso'
Natural
[()]
list =
iso
(\n -> replicate n ())
length
newtype Positive =
Positive
Integer
deriving (Eq, Ord, Show)
instance Semigroup Positive where
Positive x <> Positive y =
Positive (x + y)
instance Monoid Positive where
mappend =
(<>)
mempty =
Positive 0
class HasPositive a where
positive ::
Lens'
a
Positive
instance HasPositive Positive where
positive =
id
class AsPositive a where
_Positive ::
Prism'
a
Positive
instance AsPositive Positive where
_Positive =
id
integralPrism1 ::
Integral a =>
Prism'
a
Positive
integralPrism1 =
prism'
(\(Positive n) -> fromIntegral n)
(\n -> if n < 1 then Nothing else Just (Positive (fromIntegral n)))
instance AsPositive Int where
_Positive =
integralPrism1
instance AsPositive Integer where
_Positive =
integralPrism1
instance AsPositive Word where
_Positive =
integralPrism1
instance Integral a => AsPositive (Const a b) where
_Positive =
integralPrism1
instance Integral a => AsPositive (Identity a) where
_Positive =
integralPrism1
newtype SumPositive =
SumPositive
Positive
deriving (Eq, Ord, Show)
instance HasPositive SumPositive where
positive =
_Wrapped . positive
instance AsPositive SumPositive where
_Positive =
_Wrapped . _Positive
instance SumPositive ~ a =>
Rewrapped SumPositive a
instance Wrapped SumPositive where
type Unwrapped SumPositive = Positive
_Wrapped' =
iso
(\(SumPositive x) -> x)
SumPositive
instance Semigroup SumPositive where
SumPositive (Positive x) <> SumPositive (Positive y) =
SumPositive (Positive (x + y))
newtype MaxPositive =
MaxPositive
Positive
deriving (Eq, Ord, Show)
instance HasPositive MaxPositive where
positive =
_Wrapped . positive
instance AsPositive MaxPositive where
_Positive =
_Wrapped . _Positive
instance MaxPositive ~ a =>
Rewrapped MaxPositive a
instance Wrapped MaxPositive where
type Unwrapped MaxPositive = Positive
_Wrapped' =
iso
(\(MaxPositive x) -> x)
MaxPositive
instance Semigroup MaxPositive where
MaxPositive (Positive x) <> MaxPositive (Positive y) =
MaxPositive (Positive (x `max` y))
newtype MinPositive =
MinPositive
Positive
deriving (Eq, Ord, Show)
instance HasPositive MinPositive where
positive =
_Wrapped . positive
instance AsPositive MinPositive where
_Positive =
_Wrapped . _Positive
instance MinPositive ~ a =>
Rewrapped MinPositive a
instance Wrapped MinPositive where
type Unwrapped MinPositive = Positive
_Wrapped' =
iso
(\(MinPositive x) -> x)
MinPositive
instance Semigroup MinPositive where
MinPositive (Positive x) <> MinPositive (Positive y) =
MinPositive (Positive (x `min` y))
naturalPositive ::
Iso' Natural (Maybe Positive)
naturalPositive =
iso
(\(Natural n) ->
if n == 0 then Nothing else Just (Positive n))
(\x -> Natural (
case x of
Nothing ->
0
Just (Positive n) ->
n)
)
instance AsPositive Natural where
_Positive =
prism'
(\(Positive n) -> Natural n)
(\(Natural n) -> if n == 0 then Nothing else Just (Positive n))
one ::
Prism'
Positive
()
one =
prism'
(\() -> Positive 1)
(\(Positive n) -> if n == 1 then Just () else Nothing)
one' ::
Positive
one' =
one # ()
successor1 ::
Prism'
Positive
Positive
successor1 =
prism'
(\(Positive n) -> Positive (n + 1))
(\(Positive n) -> if n == 1 then Nothing else Just (Positive (n - 1)))
successor1' ::
Positive
-> Positive
successor1' =
(successor1 #)
successorW ::
Iso'
Natural
Positive
successorW =
iso
(\(Natural n) -> Positive (n + 1))
(\(Positive n) -> Natural (n - 1))
plus1 ::
Positive
-> Positive
-> Positive
plus1 x y =
(_Wrapped # x <> (_Wrapped # y :: SumPositive)) ^. _Wrapped
multiply1 ::
Positive
-> Positive
-> Positive
multiply1 =
(<>)
square1 ::
Positive
-> Positive
-> Positive
square1 (Positive x) (Positive y) =
Positive (x ^ y)
oneOr ::
AsPositive a =>
a
-> Positive
oneOr n =
fromMaybe one' (n ^? _Positive)
notZero ::
Prism'
Natural
Positive
notZero =
prism'
(\(Positive n) -> Natural n)
(\(Natural n) -> if n == 0 then Nothing else Just (Positive n))
length1 ::
Foldable1 f =>
f a
-> Positive
length1 x =
foldMap1 (const (SumPositive one')) x ^. _Wrapped
replicate1 ::
Positive
-> a
-> NonEmpty a
replicate1 n a =
take1 n (a :| repeat a)
take1 ::
Positive
-> NonEmpty a
-> NonEmpty a
take1 n (h:|t) =
h :| take (successorW # n) t
drop1 ::
Positive
-> NonEmpty a
-> [a]
drop1 n (_:|t) =
drop (successorW # n) t
splitAt1 ::
Positive
-> NonEmpty a
-> (NonEmpty a, [a])
splitAt1 n x =
(take1 n x, drop1 n x)
(!!!) ::
NonEmpty a
-> Positive
-> Maybe a
(_:|t) !!! n =
t !! (successorW # n)
findIndices1 ::
(a -> Bool)
-> NonEmpty a
-> [Positive]
findIndices1 p x =
map snd (NonEmpty.filter (p . fst) (NonEmpty.zip x (NonEmpty.iterate successor1' one')))
findIndex1 ::
(a -> Bool)
-> NonEmpty a
-> Maybe Positive
findIndex1 p =
listToMaybe . findIndices1 p
elemIndices1 ::
Eq a =>
a
-> NonEmpty a
-> [Positive]
elemIndices1 =
findIndices1 . (==)
elemIndex1 ::
Eq a =>
a
-> NonEmpty a
-> Maybe Positive
elemIndex1 =
findIndex1 . (==)
minus1 ::
Positive
-> Positive
-> Positive
minus1 (Positive x) (Positive y) =
Positive (if x < y then 1 else x - y)
list1 ::
Iso'
Positive
(NonEmpty ())
list1 =
iso
(\n -> replicate1 n ())
length1
plusone ::
Natural
-> Positive
plusone =
(^. successorW)
minusone ::
Positive
-> Natural
minusone =
(successorW #)