packages feed

immutaball-core-0.1.0.5.1: dependency-substitutions/wires/Control/Wire/Internal.hs

{-# OPTIONS_GHC -fno-warn-tabs #-}  -- Support tab indentation better, for a better default of no warning if tabs are used: https://dmitryfrank.com/articles/indent_with_tabs_align_with_spaces .
-- Enable warnings:
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

-- Wire/Internal.hs.

{-# LANGUAGE Haskell2010 #-}
--{-# LANGUAGE TemplateHaskell, Arrows, DerivingVia, RankNTypes #-}

-- | A rewrite of wires, sufficient for our purposes.
module Control.Wire.Internal
	(
		Wire(..),
		stepWire
	) where

import Control.Arrow
import Control.Category as C
import Control.Monad.Fix

-- | A self-modifying function.
--
-- This is the central construct in the ‘wires’ FRP implementation.
newtype Wire m a b = Wire { _wireStep :: a -> m (b, Wire m a b) }

-- | Step a wire.  Obtain its result and the next version of itself.
{-# INLINE stepWire #-}
stepWire :: Wire m a b -> a -> m (b, Wire m a b)
stepWire = _wireStep

instance (Functor m) => Functor (Wire m a) where
	{-# INLINE fmap #-}
	fmap f (Wire w) = Wire $ \a -> (\(b, w') -> (f b, fmap f w')) <$> w a

instance (Applicative m) => Applicative (Wire m i) where
	{-# INLINE pure #-}
	pure a = fix $ \me -> Wire $ \_i -> pure (a, me)
	{-# INLINE (<*>) #-}
	(Wire wf) <*> (Wire wa) = Wire $ \i -> pure (\(f, wf') (a, wa') -> (f a, wf' <*> wa')) <*> wf i <*> wa i

instance (Monad m) => Category (Wire m) where
	{-# INLINE id #-}
	id = fix $ \me -> Wire $ \a -> return (a, me)
	{-# INLINE (.) #-}
	(Wire wc) . (Wire wb) = Wire $ \a -> wb a >>= \(b, wb') -> wc b >>= \(c, wc') -> return (c, wc' C.. wb')

instance (Monad m) => Arrow (Wire m) where
	{-# INLINE arr #-}
	arr f = fix $ \me -> Wire $ \a -> pure (f a, me)
	{-# INLINE first #-}
	first (Wire w) = Wire $ \(a, d) -> (\(b, w') -> ((b, d), first w')) <$> w a

instance (Monad m) => ArrowChoice (Wire m) where
	-- (Tricky: in the Left case, don't use ‘me’ which would discard ‘w'’.)
	{-# INLINE left #-}
	left (Wire w) = fix $ \me -> Wire $ \bd -> either (\b -> (\(c, w') -> (Left c, left w')) <$> w b) (\d -> pure (Right d, me)) bd

instance (MonadFix m) => ArrowLoop (Wire m) where
	-- w :: (b, d) -> m ((c, d), Wire m (b, d) (c, d))
	--  Make sure this is lazy enough, or it could hang!
	{-# INLINE loop #-}
	loop (Wire w) = Wire $ \b -> (\((c, _d), w') -> (c, loop w')) <$> (mfix $ \ ~(~(_c, d), _w') -> w (b, d))