| Safe Haskell | None |
|---|---|
| Language | GHC2024 |
Circuit.Hyper
Description
A Hyper is completely determined by its dual. To get a b you must
provide a continuation that can itself produce an a.
Hyper is the function-category specialisation:
type Hyper = HyperA (->)
The two named targets are:
Hyper— arrows are plain functions and knots tie by Haskell laziness.— arrows are Kleisli arrows and knots tie withHyperA(Km)mfix.
They share the same newtype, but the constructors and eliminators are specialised because the two bases have different notions of observation and fixed point.
doctests
>>>import Circuit.Hyper>>>import Circuit.Channel (trace)>>>import Circuit.Category (K (..))>>>import Data.Functor.Identity (Identity (..))
>>>let body = liftK (K (\(xs, ()) -> Identity (0 : xs, take 3 xs)) :: K Identity ([Int], ()) ([Int], [Int]))>>>runIdentity (observeK (trace body) ())[0,0,0]
Synopsis
- newtype HyperA (arr :: Type -> k -> Type) (a :: k) (b :: k) = HyperA {}
- type Hyper = HyperA (->)
- pattern Hyper :: (HyperA (->) b a -> b) -> Hyper a b
- lift :: (a -> b) -> Hyper a b
- observe :: Hyper a b -> a -> b
- base :: a -> Hyper b a
- push :: (a -> b) -> Hyper a b -> Hyper a b
- runHyper :: Hyper a a -> a
- liftK :: forall (m :: Type -> Type) a b. Monad m => K m a b -> HyperA (K m) a b
- observeK :: Monad m => HyperA (K m) a b -> a -> m b
- baseK :: forall (m :: Type -> Type) b a. Monad m => b -> HyperA (K m) a b
- pushK :: forall (m :: Type -> Type) a b. Monad m => K m a b -> HyperA (K m) a b -> HyperA (K m) a b
- runHyperK :: MonadFix m => HyperA (K m) a a -> m a
- encodeEither :: (Either a b -> Either a c) -> Hyper (Either a b -> c) (Either a b -> c)
- runEither :: (Either a b -> Either a c) -> b -> c
- encode :: Trace (,) (->) a b -> Hyper a b
- encodeK :: forall (m :: Type -> Type) a b. MonadFix m => Trace (,) (K m) a b -> HyperA (K m) a b
Parameterised hyperfunctions
newtype HyperA (arr :: Type -> k -> Type) (a :: k) (b :: k) Source #
A hyperfunction from a to b over the base category arr.
Constructors
| HyperA | |
Instances
| Category Hyper Source # | |
| Channel (,) Hyper Source # | |
| Strength (,) Hyper Source # | |
| Traced (,) Hyper Source # | |
| Monad m => Channel (,) (HyperA (K m) :: Type -> Type -> Type) Source # | |
| Monad m => Strength (,) (HyperA (K m) :: Type -> Type -> Type) Source # | |
| MonadFix m => Traced (,) (HyperA (K m) :: Type -> Type -> Type) Source # | |
| Monad m => Category (HyperA (K m) :: Type -> Type -> Type) Source # | |
pattern Hyper :: (HyperA (->) b a -> b) -> Hyper a b Source #
Bidirectional pattern for the function-category hyperfunction.
Function-category hyperfunctions
lift :: (a -> b) -> Hyper a b Source #
Embed a plain function into a hyperfunction.
>>>observe (lift (+1)) 56
observe :: Hyper a b -> a -> b Source #
Extract a plain function from a hyperfunction.
>>>observe (lift reverse) "hello""olleh"
base :: a -> Hyper b a Source #
Ignores the input and returns a constant value.
>>>observe (base 42) undefined42
push :: (a -> b) -> Hyper a b -> Hyper a b Source #
Push a plain function onto a hyperfunction.
>>>observe (push (+1) (lift (*2))) 56
runHyper :: Hyper a a -> a Source #
Close the self-referential loop.
>>>runHyper (Hyper $ \_ -> 42 :: Int)42
Kleisli hyperfunctions
liftK :: forall (m :: Type -> Type) a b. Monad m => K m a b -> HyperA (K m) a b Source #
Embed a Kleisli arrow into a hyperfunction.
observeK :: Monad m => HyperA (K m) a b -> a -> m b Source #
Extract the underlying Kleisli arrow from a hyperfunction.
baseK :: forall (m :: Type -> Type) b a. Monad m => b -> HyperA (K m) a b Source #
A constant Kleisli hyperfunction.
pushK :: forall (m :: Type -> Type) a b. Monad m => K m a b -> HyperA (K m) a b -> HyperA (K m) a b Source #
Push a Kleisli arrow onto a hyperfunction.
runHyperK :: MonadFix m => HyperA (K m) a a -> m a Source #
Close the self-referential loop using mfix.
Either-loop state machine
encodeEither :: (Either a b -> Either a c) -> Hyper (Either a b -> c) (Either a b -> c) Source #
Encode an Either-loop as a self-referential Hyper.
Whereas encode handles the (,) tensor using Hyper's own Traced
instance, this preserves the Either-loop state in the function domain.
Left a feeds back; Right c terminates with output.
>>>:{let step = \case Right n | n < 3 -> Left (n + 1) Right n -> Right n Left n | n < 3 -> Left (n + 1) Left n -> Right n :}
>>>runEither step (0 :: Int)3
runEither :: (Either a b -> Either a c) -> b -> c Source #
Run an encodeEither-encoded circuit from initial input b.
encodeEither embeds the Either state machine into Hyper, runHyper
ties the self-referential knot, and Right b injects the initial state.
>>>:{let step = \case Right n | n < 3 -> Left (n + 1) Right n -> Right n Left n | n < 3 -> Left (n + 1) Left n -> Right n :}
>>>runEither step (0 :: Int)3
Bridges from initial syntax
encode :: Trace (,) (->) a b -> Hyper a b Source #
Encode a function-category Trace into a Hyper.
This is the unique traced functor from the initial syntax (Trace)
to the final object (Hyper), satisfying the commuting triangle
.observe . encode = eval
base constructors embed directly via lift; yank
constructors become trace over a hyperfunction.
>>>import qualified Circuit.Trace as Trace>>>observe (encode (Trace.base (+1) :: Trace.Trace (,) (->) Int Int)) 56