alms-0.6.0: src/Type/Reduce.hs
{-# LANGUAGE TypeFamilies #-}
module Type.Reduce (
matchReduce,
headNormalizeTypeK, headNormalizeType,
headReduceType, ReductionState(..),
majorReductionSequence, reductionSequence, reductionSequence'
) where
import Util
import Error
import Type.Internal
import Type.TyVar (Tv)
import Type.Ppr ()
import Prelude ()
import Data.Generics (Typeable, Data)
import qualified Data.List as List
instance Tv tv ⇒ Viewable (Type tv) where
type View (Type tv) = Type tv
view = headNormalizeTypeK 1000
-- | Reduce a type to head normal form
headNormalizeType ∷ Ord tv ⇒ Type tv → Type tv
headNormalizeType = last . reductionSequence
-- | Allow @k0@ steps to reduce a type to head normal form, or call
-- 'error'
headNormalizeTypeK ∷ Tv tv ⇒ Int → Type tv → Type tv
headNormalizeTypeK k0 σ0 = loop k0 (reductionSequence σ0) where
loop _ [] = throw $
almsBug StaticsPhase "headNormalizeTypeK"
"got empty reduction sequence"
loop _ [σ] = σ
loop 0 (σ:_) = throw $
AlmsError StaticsPhase bogus
[msg|
Reduction of type $q:σ0 has not converged after $k0
steps; stopped at $q:σ.
|]
loop k (_:σs) = loop (k - 1) σs
-- | Given two types, try to reduce them to a pair with a common
-- head constructor. We assume that the two types given don't
-- match in the head already.
matchReduce ∷ Ord tv ⇒ Type tv → Type tv → Maybe (Type tv, Type tv)
matchReduce σ1 σ2 =
List.find isCandidate
(safeTail (allPairsBFS (majorReductionSequence σ1)
(majorReductionSequence σ2)))
where
isCandidate (TyApp tc _, TyApp tc' _) = tc == tc'
isCandidate _ = True
safeTail [] = []
safeTail (_:σs) = σs
-- | Returns all pairs of a pair of lists, breadth first
allPairsBFS ∷ [a] → [b] → [(a, b)]
allPairsBFS xs0 ys0 = loop [(xs0, ys0)] where
loop [] = []
loop xsys = [ (x, y) | (x:_, y:_) ← xsys ]
++ loop (take 1 [ (xs, ys) | (xs, _:ys) ← xsys ]
++ [ (xs, ys) | (_:xs, ys) ← xsys ])
-- | A major reduction sequence is a reduction sequence filtered
-- to show only changes in the head constructor.
majorReductionSequence ∷ Ord tv ⇒ Type tv → [Type tv]
majorReductionSequence = clean . reductionSequence where
clean [] = []
clean (σ:σs) = σ : cleanWith σ σs
cleanWith σ@(TyApp tc _) ((TyApp tc' _) : σs)
| tc == tc' = cleanWith σ σs
cleanWith _ σs = clean σs
-- | The reduction sequence of a type
reductionSequence ∷ Ord tv ⇒ Type tv → [Type tv]
reductionSequence σ = (σ:) $ case headReduceType σ of
Next σ' → reductionSequence σ'
_ → []
-- | The reduction sequence of a type along with a final status
-- indicator
reductionSequence' ∷ Ord tv ⇒ Type tv → ([Type tv], ReductionState ())
reductionSequence' σ = first (σ:) $ case headReduceType σ of
Next σ' → reductionSequence' σ'
rs → ([], () <$ rs)
-- | The state of a type reduction
data ReductionState t
-- | The type is head-normal -- that is, its head constructor is
-- not a type synonym/operator
= Done
-- | The type has a next head-reduction step
| Next t
-- | The type may reduce further in the future, but right now it
-- has a pattern match that depends on the value of a type variable
| Blocked
-- | The type's head constructor is a synonym/operator, but it
-- can never take a step, due to a failed pattern match
| Stuck
deriving (Eq, Ord, Show, Functor, Typeable, Data)
-- | Perform one head reduction step.
headReduceType ∷ Ord tv ⇒ Type tv → ReductionState (Type tv)
headReduceType σ0 = case σ0 of
TyQu _ _ _ → Done
TyVar _ → Done
TyRow _ _ _ → Done
TyMu _ σ → Next $ openTy 0 [σ0] σ
TyApp tc [σ1, σ2] | tc == tcRowMap
→ applyRowMap σ1 σ2
TyApp tc σs → maybe Done (clauses tc σs) (tcNext tc)
where
--
clauses _ _ [] = Stuck
clauses tc σs ((tps, rhs):rest) = case patts tps σs of
Right σs' → Next $ openTy 0 σs' (elimEmptyF rhs)
Left Stuck → clauses tc σs rest
Left rs → TyApp tc <$> rs
--
patts [] [] = Right []
patts (tp:tps) (σ:σs) = case patt tp σ of
Right σs' → case patts tps σs of
Right σss' → Right (σs' ++ σss')
Left rs → Left ((σ:) <$> rs)
Left Blocked → Left $ either ((σ:) <$>) (const Blocked) (patts tps σs)
Left rs → Left $ (:σs) <$> rs
patts _ _ = Left Stuck
--
patt (TpVar _) σ = Right [σ]
patt (TpApp tc tps) σ = case σ of
TyApp tc' σs
| tc == tc' → ((TyApp tc' <$>) +++ id) (patts tps σs)
TyVar _ → Left Blocked
_ → case headReduceType σ of
Done → Left Stuck
rs → Left rs
patt (TpRow _) σ = Right [σ]
applyRowMap ∷ Ord tv ⇒ Type tv → Type tv → ReductionState (Type tv)
applyRowMap σcxt σarg = case σarg of
TyRow lab σ1 σ2
→ Next $ TyRow lab (plugHole σcxt σ1) (tyRowMap σcxt σ2)
TyApp tc [] | tc == tcRowEnd
→ Next tyRowEnd
_ → tyRowMap σcxt <$> headReduceType σarg
plugHole ∷ Ord tv ⇒ Type tv → Type tv → Type tv
plugHole σcxt σ' = foldType (mkQuF TyQu) (mkBvF bvTy) fvTy fcon
TyRow (mkMuF TyMu) σcxt
where
fcon tc σs =
if tc == tcRowHole
then σ'
else TyApp tc σs