{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RecordWildCards #-} module LiveCoding.Migrate.Cell where -- base import Data.Data -- syb import Data.Generics.Aliases -- essence-of-live-coding import LiveCoding.Cell import LiveCoding.Cell.Feedback import LiveCoding.Exceptions import LiveCoding.Migrate.Migration import Control.Applicative (Alternative((<|>))) -- * Migrations to and from pairs -- ** Generic migration functions -- | Builds the migration function for a pair, or product type, -- such as tuples, but customisable to your own products. -- You need to pass it the equivalents of 'fst', 'snd', and '(,)'. -- Tries to migrate the value into the first element, then into the second. maybeMigrateToPair :: (Typeable a, Typeable b, Typeable c) => (t a b -> a) -- ^ The accessor of the first element -> (t a b -> b) -- ^ The accessor of the second element -> (a -> b -> t a b) -- ^ The constructor -> t a b -- ^ The pair -> c -- ^ The new value for the first or second element -> Maybe (t a b) maybeMigrateToPair fst snd cons pair c = do flip cons (snd pair) <$> cast c <|> cons (fst pair) <$> cast c -- | Like 'maybeMigrateToPair', but in the other direction. -- Again, it is biased with respect to the first element of the pair. maybeMigrateFromPair :: (Typeable a, Typeable b, Typeable c) => (t a b -> a) -- ^ The accessor of the first element -> (t a b -> b) -- ^ The accessor of the second element -> t a b -> Maybe c maybeMigrateFromPair fst snd pair = cast (fst pair) <|> cast (snd pair) -- ** Migrations involving sequential compositions of cells -- | Migrate @cell@ to @cell >>> cell'@, and if this fails, to @cell' >>> cell@. migrationToComposition :: Migration migrationToComposition = migrationTo2 $ maybeMigrateToPair state1 state2 Composition -- | Migrate @cell1 >>> cell2@ to @cell1@, and if this fails, to @cell2@. migrationFromComposition :: Migration migrationFromComposition = constMigrationFrom2 $ maybeMigrateFromPair state1 state2 -- | Combines all migrations related to composition, favouring migration to compositions. migrationComposition :: Migration migrationComposition = migrationToComposition <> migrationFromComposition -- ** Migrations involving parallel compositions of cells -- | Migrate @cell@ to @cell *** cell'@, and if this fails, to @cell' *** cell@. migrationToParallel :: Migration migrationToParallel = migrationTo2 $ maybeMigrateToPair stateP1 stateP2 Parallel -- | Migrate from @cell1 *** cell2@ to @cell1@, and if this fails, to @cell2@. migrationFromParallel :: Migration migrationFromParallel = constMigrationFrom2 $ maybeMigrateFromPair stateP1 stateP2 -- | Combines all migrations related to parallel composition, favouring migration to parallel composition. migrationParallel :: Migration migrationParallel = migrationToParallel <> migrationFromParallel -- ** Migration involving 'ArrowChoice' -- | Migrate @cell@ to @cell ||| cell'@, and if this fails, to @cell' ||| cell@. migrationToChoice :: Migration migrationToChoice = migrationTo2 $ maybeMigrateToPair choiceLeft choiceRight Choice -- | Migrate from @cell1 ||| cell2@ to @cell1@, and if this fails, to @cell2@. migrationFromChoice :: Migration migrationFromChoice = constMigrationFrom2 $ maybeMigrateFromPair choiceLeft choiceRight -- | Combines all migrations related to choice, favouring migration to choice. migrationChoice :: Migration migrationChoice = migrationToChoice <> migrationFromChoice -- ** Feedback -- | Migrate from @cell@ to @feedback s cell@, and if this fails, to @feedback (cellState cell) cell'@. migrationToFeedback :: Migration migrationToFeedback = migrationTo2 $ maybeMigrateToPair sPrevious sAdditional Feedback -- | Migrate from @feedback s cell@ to @cell@, and if this fails, to @Cell { cellState = s, .. }@. migrationFromFeedback :: Migration migrationFromFeedback = constMigrationFrom2 $ maybeMigrateFromPair sPrevious sAdditional -- | Combines all migrations related to feedback, favouring migration to feedback. migrationFeedback :: Migration migrationFeedback = migrationToFeedback <> migrationFromFeedback -- * Control flow maybeMigrateToExceptState :: (Typeable state, Typeable state') => ExceptState state e -> state' -> Maybe (ExceptState state e) maybeMigrateToExceptState (NotThrown _) state = NotThrown <$> cast state maybeMigrateToExceptState (Exception e) _ = Just $ Exception e -- | Migration from @cell2@ to @try cell1 >> safe cell2@ migrationToExceptState :: Migration migrationToExceptState = migrationTo2 maybeMigrateToExceptState maybeMigrateFromExceptState :: (Typeable state, Typeable state') => ExceptState state e -> Maybe state' maybeMigrateFromExceptState (NotThrown state) = cast state maybeMigrateFromExceptState (Exception e) = Nothing -- | Migration from @try cell1 >> safe cell2@ to @cell2@ migrationFromExceptState :: Migration migrationFromExceptState = constMigrationFrom2 maybeMigrateFromExceptState -- | Combines all control flow related migrations migrationExceptState :: Migration migrationExceptState = migrationToExceptState <> migrationFromExceptState -- * Overall migration -- | Combines all 'Cell'-related migrations. migrationCell :: Migration migrationCell = migrationComposition <> migrationParallel <> migrationChoice <> migrationExceptState <> migrationFeedback