{-# language CPP #-}
{-# language RankNTypes #-}
{-# language PatternGuards #-}
#if __GLASGOW_HASKELL__ >= 710
{-# language ViewPatterns #-}
{-# language PatternSynonyms #-}
#endif
--------------------------------------------------------------------------------
-- |
-- Module      :  Numeric.Natural.Lens
-- Copyright   :  (C) 2017 Edward Kmett
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
-- Stability   :  provisional
-- Portability :  portable
--
-- Useful tools for Gödel numbering.
-------------------------------------------------------------------------------
module Numeric.Natural.Lens
  ( _Pair
  , _Sum
  , _Naturals
#if __GLASGOW_HASKELL__ >= 710
  , pattern Pair
  , pattern Sum
  , pattern Naturals
#endif
  ) where

import Control.Lens
import Numeric.Natural

-- | The natural numbers are isomorphic to the product of the natural numbers with itself.
--
-- @N = N*N@
_Pair :: Iso' Natural (Natural, Natural)
_Pair :: p (Natural, Natural) (f (Natural, Natural))
-> p Natural (f Natural)
_Pair = (Natural -> (Natural, Natural))
-> ((Natural, Natural) -> Natural)
-> Iso Natural Natural (Natural, Natural) (Natural, Natural)
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso Natural -> (Natural, Natural)
forall b. Integral b => b -> (b, b)
hither ((Natural -> Natural -> Natural) -> (Natural, Natural) -> Natural
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Natural -> Natural -> Natural
forall t. Integral t => t -> t -> t
yon) where
  yon :: t -> t -> t
yon 0 0 = 0
  yon m :: t
m n :: t
n = case t -> t -> (t, t)
forall a. Integral a => a -> a -> (a, a)
quotRem t
m 2 of
    (q :: t
q,r :: t
r) -> t
r t -> t -> t
forall a. Num a => a -> a -> a
+ 2 t -> t -> t
forall a. Num a => a -> a -> a
* t -> t -> t
yon t
n t
q -- rotation

  hither :: b -> (b, b)
hither 0 = (0,0)
  hither n :: b
n = case b -> b -> (b, b)
forall a. Integral a => a -> a -> (a, a)
quotRem b
n 2 of
   (p :: b
p,r :: b
r) -> case b -> (b, b)
hither b
p of
     (x :: b
x,y :: b
y) -> (b
rb -> b -> b
forall a. Num a => a -> a -> a
+2b -> b -> b
forall a. Num a => a -> a -> a
*b
y,b
x) -- rotation

-- | The natural numbers are isomorphic to disjoint sums of natural numbers embedded as
-- evens or odds.
--
-- @N = 2*N@
_Sum :: Iso' Natural (Either Natural Natural)
_Sum :: p (Either Natural Natural) (f (Either Natural Natural))
-> p Natural (f Natural)
_Sum = (Natural -> Either Natural Natural)
-> (Either Natural Natural -> Natural)
-> Iso
     Natural Natural (Either Natural Natural) (Either Natural Natural)
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso Natural -> Either Natural Natural
forall b. Integral b => b -> Either b b
hither Either Natural Natural -> Natural
forall p. Num p => Either p p -> p
yon where
  hither :: b -> Either b b
hither p :: b
p = case b -> b -> (b, b)
forall a. Integral a => a -> a -> (a, a)
quotRem b
p 2 of
    (q :: b
q,0) -> b -> Either b b
forall a b. a -> Either a b
Left b
q
    (q :: b
q,1) -> b -> Either b b
forall a b. b -> Either a b
Right b
q
    _     -> [Char] -> Either b b
forall a. HasCallStack => [Char] -> a
error "_Sum: impossible"
  yon :: Either p p -> p
yon (Left q :: p
q)  = 2p -> p -> p
forall a. Num a => a -> a -> a
*p
q
  yon (Right q :: p
q) = 2p -> p -> p
forall a. Num a => a -> a -> a
*p
qp -> p -> p
forall a. Num a => a -> a -> a
+1

-- | The natural numbers are isomorphic to lists of natural numbers
_Naturals :: Iso' Natural [Natural]
_Naturals :: p [Natural] (f [Natural]) -> p Natural (f Natural)
_Naturals = (Natural -> [Natural])
-> ([Natural] -> Natural)
-> Iso Natural Natural [Natural] [Natural]
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso Natural -> [Natural]
hither [Natural] -> Natural
yon where
  hither :: Natural -> [Natural]
hither 0 = []
  hither n :: Natural
n | (h :: Natural
h, t :: Natural
t) <- (Natural
nNatural -> Natural -> Natural
forall a. Num a => a -> a -> a
-1)Natural
-> Getting (Natural, Natural) Natural (Natural, Natural)
-> (Natural, Natural)
forall s a. s -> Getting a s a -> a
^.Getting (Natural, Natural) Natural (Natural, Natural)
Iso Natural Natural (Natural, Natural) (Natural, Natural)
_Pair = Natural
h Natural -> [Natural] -> [Natural]
forall a. a -> [a] -> [a]
: Natural -> [Natural]
hither Natural
t
  yon :: [Natural] -> Natural
yon [] = 0
  yon (x :: Natural
x:xs :: [Natural]
xs) = 1 Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ AReview Natural (Natural, Natural) -> (Natural, Natural) -> Natural
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview Natural (Natural, Natural)
Iso Natural Natural (Natural, Natural) (Natural, Natural)
_Pair (Natural
x, [Natural] -> Natural
yon [Natural]
xs)

#if __GLASGOW_HASKELL__ >= 710

-- |
-- interleaves the bits of two natural numbers
pattern Pair :: Natural -> Natural -> Natural
pattern $bPair :: Natural -> Natural -> Natural
$mPair :: forall r. Natural -> (Natural -> Natural -> r) -> (Void# -> r) -> r
Pair x y <- (view _Pair -> (x,y)) where
  Pair x :: Natural
x y :: Natural
y = AReview Natural (Natural, Natural) -> (Natural, Natural) -> Natural
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview Natural (Natural, Natural)
Iso Natural Natural (Natural, Natural) (Natural, Natural)
_Pair (Natural
x,Natural
y)

-- |
-- @
-- Sum (Left q) = 2*q
-- Sum (Right q) = 2*q+1
-- @
pattern Sum :: Either Natural Natural -> Natural
pattern $bSum :: Either Natural Natural -> Natural
$mSum :: forall r.
Natural -> (Either Natural Natural -> r) -> (Void# -> r) -> r
Sum s <- (view _Sum -> s) where
  Sum s :: Either Natural Natural
s = AReview Natural (Either Natural Natural)
-> Either Natural Natural -> Natural
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview Natural (Either Natural Natural)
Iso
  Natural Natural (Either Natural Natural) (Either Natural Natural)
_Sum Either Natural Natural
s

-- |
-- @
-- Naturals [] = 0
-- Naturals (h:t) = 1 + Pair h (Naturals t)
-- @
pattern Naturals :: [Natural] -> Natural
pattern $bNaturals :: [Natural] -> Natural
$mNaturals :: forall r. Natural -> ([Natural] -> r) -> (Void# -> r) -> r
Naturals xs <- (view _Naturals -> xs) where
  Naturals xs :: [Natural]
xs = AReview Natural [Natural] -> [Natural] -> Natural
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview Natural [Natural]
Iso Natural Natural [Natural] [Natural]
_Naturals [Natural]
xs
#endif