packages feed

lol-typing-1.20160822: Language/LOL/Typing/Type/Polytype.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-tabs #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Language.LOL.Typing.Type.Polytype where

import Data.Bool
import qualified Data.Foldable as Foldable
import Data.Functor ((<$>))
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Function ((.), id)
import qualified Data.List as List
import Data.Monoid ((<>))
import Data.Text.Buildable (Buildable(..))
import Text.Show (Show(..))

import Language.LOL.Typing.Type.Monotype
import Language.LOL.Typing.Type.Substitution
import Language.LOL.Typing.Type.Quantification
import Language.LOL.Typing.Type.Qualification
import Language.LOL.Typing.Type.Class
import Language.LOL.Typing.Lib.Data.Default (Default(..))

-- * Type 'Polytype'

-- | A /rank-1 polymorphic type/ (aka. /polytype/), with qualifiers.
type Polytype
 = Forall (Qualification [Class_Qualifier] Monotype)
instance Buildable Polytype where
	build x = build (def::Quantification_Build_Options, x)
instance Has_Monoconsts Polytype where
	monoconsts Quantification{quantified = Qualification quals monoty} =
		Map.unions (monoconsts monoty : (monoconsts <$> quals))

-- | Return a 'Polytype' /generalizing/ the given 'Monotype':
--
-- * quantifying all its 'Monovar's (which thus become /polymorphic/)
--   except the given 'Monovar's (which thus remain /monomorphic/),
-- * and qualifying them by the given 'Class_Qualifier's
--   which use at least one of them.
polytype_but
 :: [Monovar] -> [Class_Qualifier]
 -> Monotype -> Polytype
polytype_but vars_mono quals monoty =
	forall_in vars_poly Qualification
	 { qualifiers = List.filter is_quantified quals
	 , qualified  = monoty
	 }
	where
	vars_poly = subvars monoty List.\\ vars_mono
	is_quantified = Foldable.any (`List.elem` vars_poly) . subvars

-- | A /type with qualifiers/, constructed from a 'Monotype'
-- and some 'Class_Qualifier's (aka. /class context/).
--
-- These 'Class_Qualifier's put restrictions on certain 'Monovar's.
type Qualified_Type
 =   Qualification [Class_Qualifier] Monotype

-- ** Class 'Polytypeable'

-- | A type class to convert something into a 'Polytype'
class Polytypeable a where
	polytype :: a -> Polytype
instance Polytypeable Monotype where
	polytype = quantification . ([] .=>.)
instance Polytypeable (Qualification [Class_Qualifier] Monotype) where
	polytype = quantification
instance Polytypeable Polytype where
	polytype = id

-- | Return the 'Arity' of a 'Polytype'.
polytype_arity :: Polytype -> Arity
polytype_arity = type_arity . qualified . quantified

-- | Return whether the given 'Polytype' contains 'Class_Qualifier's.
is_polytype_qualified :: Polytype -> Bool
is_polytype_qualified = not . Foldable.null . qualifiers . quantified

-- * Type 'Polysub'

-- | A /polymorphic type substitution/.
type Polysub = Map Polyvar Polytype

-- | A /polymorphic type variable/:
-- a place-holder for a 'Polytype' that is not yet known,
-- but that become available at some time during 'Constraint' solving.
--
-- NOTE: is to 'Polytype', what a 'Monovar' is to a 'Monotype'.
type Polyvar = Quantifier

-- * Type 'Polytyref'

data Polytyref
 =   Polytyref     Polytype
 |   Polytyref_Var Polyvar
 deriving (Show)

instance Buildable Polytyref where
	build r =
		case r of
		 Polytyref polyty -> build (def::Quantification_Build_Options, polyty)
		 Polytyref_Var v  -> "p" <> build v
instance Substitutable Polytyref where
	subvars (Polytyref polyty) = subvars polyty
	subvars (Polytyref_Var _)  = []
	
	_   `substitute` r@(Polytyref_Var _) = r
	sub `substitute` (Polytyref s)       = Polytyref (sub `substitute` s)

-- ** Class 'Polytyrefable'

class Polytyrefable a where
	polytyref :: a -> Polytyref

instance Polytyrefable Monotype       where polytyref = Polytyref . polytype
instance Polytyrefable Polytype       where polytyref = Polytyref . polytype
instance Polytyrefable Polytyref      where polytyref = id
instance Polytyrefable Polyvar        where polytyref = Polytyref_Var
instance Polytyrefable Qualified_Type where polytyref = Polytyref . polytype