{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Language.LOL.Symantic.Expr.Common where

import Data.Proxy (Proxy(..))
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Type.Equality ((:~:)(Refl))
import GHC.Prim (Constraint)

import Language.LOL.Symantic.Type

-- * Class 'Expr_from'

-- | Parse given @ast@ into
-- a 'Type_Root_of_Expr' and
-- a 'Forall_Repr_with_Context',
-- or return an 'Error_of_Expr'.
class Expr_from ast (ex:: *) where
	expr_from :: Expr_From ast ex hs ret

-- ** Type 'Expr_From'
type Expr_From ast ex hs ret
 = Proxy ex
 -- ^ Select the 'Expr_from' instance.
 -> ast
 -- ^ The input data to parse.
 -> Context (Lambda_Var (Type_Root_of_Expr ex)) hs
 -- ^ The bound variables in scope and their types:
 -- held in the heterogeneous list @hs@,
 -- from the closest including lambda abstraction to the farest.
 -> ( forall h
    .  Type_Root_of_Expr ex h
    -> Forall_Repr_with_Context ex hs h
    -> Either (Error_of_Expr ast (Root_of_Expr ex)) ret )
 -- ^ The accumulating continuation.
 ->    Either (Error_of_Expr ast (Root_of_Expr ex)) ret

-- | Parse a literal.
lit_from
 :: forall ty lit ex ast hs ret.
 ( ty ~ Type_Root_of_Expr ex
 , Read lit
 , Error_Expr_Lift (Error_Expr (Error_of_Type ast ty) ty ast)
                   (Error_of_Expr ast (Root_of_Expr ex))
 ) => (forall repr. Sym_of_Expr ex repr => lit -> repr lit)
 -> ty lit -> Lambda_Var_Name
 -> Expr_From ast ex hs ret
lit_from lit ty_lit toread ex ast _ctx k =
	case read_safe toread of
	 Left err -> Left $ error_expr ex $ Error_Expr_Read err ast
	 Right (i::lit) -> k ty_lit $ Forall_Repr_with_Context $ const $ lit i

-- | Parse a unary operator.
op1_from
 :: forall root ty lit ex ast hs ret.
 ( ty ~ Type_Root_of_Expr ex
 , root ~ Root_of_Expr ex
 , Type_Eq (Type_Root_of_Expr root)
 , Expr_from ast root
 , Error_Expr_Lift (Error_Expr (Error_of_Type ast ty) ty ast)
                   (Error_of_Expr ast root)
 , Root_of_Expr root ~ root
 ) => (forall repr. Sym_of_Expr ex repr => repr lit -> repr lit)
 -> ty lit -> ast
 -> Expr_From ast ex hs ret
op1_from op ty_lit ast_x ex ast ctx k =
	expr_from (Proxy::Proxy root) ast_x ctx $
	 \ty_x (Forall_Repr_with_Context x) ->
	when_type_eq ex ast ty_lit ty_x $ \Refl ->
		k ty_x $ Forall_Repr_with_Context (op . x)

-- | Parse a binary operator.
op2_from
 :: forall root ty lit ex ast hs ret.
 ( ty ~ Type_Root_of_Expr ex
 , root ~ Root_of_Expr ex
 , Type_Eq (Type_Root_of_Expr root)
 , Expr_from ast root
 , Error_Expr_Lift (Error_Expr (Error_of_Type ast ty) ty ast)
                   (Error_of_Expr ast root)
 , Root_of_Expr root ~ root
 ) => (forall repr. Sym_of_Expr ex repr => repr lit -> repr lit -> repr lit)
 -> ty lit -> ast -> ast
 -> Expr_From ast ex hs ret
op2_from op ty_lit ast_x ast_y ex ast ctx k =
	expr_from (Proxy::Proxy root) ast_x ctx $ \ty_x (Forall_Repr_with_Context x) ->
	expr_from (Proxy::Proxy root) ast_y ctx $ \ty_y (Forall_Repr_with_Context y) ->
	when_type_eq ex ast ty_lit ty_x $ \Refl ->
	when_type_eq ex ast ty_lit ty_y $ \Refl ->
		k ty_x $ Forall_Repr_with_Context $
		 \c -> x c `op` y c

-- ** Type 'Context'

-- | GADT for a typing context,
-- accumulating an @item@ at each lambda;
-- used to accumulate object-types (in 'Expr_from')
-- or host-terms (in 'Repr_Host')
-- associated with the 'Lambda_Var's in scope.
data Context :: (* -> *) -> [*] -> * where
	Context_Empty :: Context item '[]
	Context_Next  :: item h -> Context item hs -> Context item (h ': hs)
infixr 5 `Context_Next`

-- ** Type 'Lambda_Var'
-- | Join a name and a type.
--
-- This data type is used to handle lambda variables by name
-- (instead of DeBruijn indices for instance).
data Lambda_Var ty h
 =   Lambda_Var Lambda_Var_Name (ty h)
type Lambda_Var_Name = Text

-- ** Type 'Forall_Repr_with_Context'
-- | A data type embedding a universal quantification
-- over an interpreter @repr@
-- and qualified by the symantics of an expression.
--
-- Moreover the expression is abstracted by a 'Context'
-- built at parsing time to build a /Higher-Order Abstract Syntax/ (HOAS)
-- for lambda abstractions.
--
-- This data type is used to keep a parsed expression polymorphic enough
-- to stay interpretable by different interpreters.
--
-- NOTE: 'Sym_of_Expr'@ ex repr@
-- is needed to be able to use symantic methods of the parsed expression
-- into a 'Forall_Repr_with_Context'@ ex@.
--
-- NOTE: 'Sym_of_Expr'@ (@'Root_of_Expr'@ ex) repr@
-- is needed to be able to use an expression
-- out of a 'Forall_Repr_with_Context'@ (@'Root_of_Expr'@ ex)@
-- into a 'Forall_Repr_with_Context'@ ex@,
-- which happens when a symantic method includes a polymorphic type
-- and thus calls: 'expr_from'@ (Proxy::Proxy (@'Root_of_Expr'@ ex))@.
data Forall_Repr_with_Context ex hs h
 =   Forall_Repr_with_Context
 (   forall repr. ( Sym_of_Expr ex repr
                  , Sym_of_Expr (Root_of_Expr ex) repr
                  ) => Context repr hs -> repr h )

-- ** Type 'Forall_Repr'
data Forall_Repr ex h
 =   Forall_Repr
 { unForall_Repr :: forall repr
                 .  Sym_of_Expr ex repr
                 => repr h }

-- ** Type family 'Root_of_Expr'
-- | The root expression of an expression.
type family Root_of_Expr (ex:: *) :: *

-- ** Type family 'Sym_of_Expr'
-- | The symantic of an expression.
type family Sym_of_Expr (ex:: *) (repr:: * -> *) :: Constraint

-- ** Type family 'Error_of_Expr'
-- | The error(s) of an expression.
type family Error_of_Expr (ast:: *) (ex:: *) :: *

-- ** Type family 'Type_of_Expr'
-- | The type of an expression, parameterized by a root type.
type family Type_of_Expr (ex:: *) :: {-root-}(* -> *) -> {-h-}* -> *

-- ** Type 'Type_Root_of_Expr'
-- | Convenient alias.
--
-- NOTE: include 'Type_Var' only to use it
-- within 'Error_Expr_Type_mismatch' so far.
type Type_Root_of_Expr (ex:: *)
 =   Type_Root (Type_Alt Type_Var (Type_of_Expr (Root_of_Expr ex)))

-- * Type 'Expr_Root'
-- | The root expression, passing itself as parameter to the given expression.
newtype Expr_Root (ex:: * -> *)
 =      Expr_Root (ex (Expr_Root ex))
type instance Root_of_Expr (Expr_Root ex) = Expr_Root ex
type instance Type_of_Expr (Expr_Root ex)
 =            Type_of_Expr (ex (Expr_Root ex))
type instance Error_of_Expr ast (Expr_Root ex)
 =            Error_Expr_Alt (Error_Expr (Error_of_Type ast (Type_Root_of_Expr (ex (Expr_Root ex))))
                                         (Type_Root_of_Expr (ex (Expr_Root ex)))
                                         ast)
                             (Error_of_Expr ast (ex (Expr_Root ex)))
type instance Sym_of_Expr (Expr_Root ex) repr
 =            Sym_of_Expr (ex (Expr_Root ex)) repr
instance -- Expr_from
 ( Expr_from ast (ex (Expr_Root ex))
 , Root_of_Expr (ex (Expr_Root ex)) ~ Expr_Root ex
 ) => Expr_from ast (Expr_Root ex) where
	expr_from _ex ctx ast k =
		expr_from (Proxy::Proxy (ex (Expr_Root ex)))
		 ctx ast $ \ty (Forall_Repr_with_Context repr) ->
			k ty (Forall_Repr_with_Context repr)

{- NOTE: useless code so far.
-- ** Class 'Expr_Root_Lift'
-- | Lift a given expression to a given root expression.
class Expr_Root_Lift ex root where
	expr_root_lift :: ex root -> root
instance
 Expr_Lift ex root =>
 Expr_Root_Lift ex (Expr_Root root) where
	expr_root_lift = Expr_Root . expr_lift
-}

-- * Type 'Expr_Alt'
-- | Expression making an alternative between two expressions.
data Expr_Alt curr next (root:: *)
 =   Expr_Alt_Curr (curr root)
 |   Expr_Alt_Next (next root)
type instance Root_of_Expr (Expr_Alt curr next root) = root
type instance Sym_of_Expr (Expr_Alt curr next root) repr
 = ( Sym_of_Expr (curr root) repr
   , Sym_of_Expr (next root) repr
   )
type instance Type_of_Expr (Expr_Alt curr next root)
 = Type_of_Expr_Alt
  (Type_of_Expr (curr root))
  (Type_of_Expr (next root))
  curr next root
-- ** Type family 'Type_of_Expr_Alt'
-- | Remove 'No_Type' type when building 'Type_of_Expr'.
type family Type_of_Expr_Alt
 (type_curr:: (* -> *) -> * -> *)
 (type_next:: (* -> *) -> * -> *)
 curr next root where
	Type_of_Expr_Alt No_Type type_next curr next root = Type_of_Expr (next root)
	Type_of_Expr_Alt type_curr No_Type curr next root = Type_of_Expr (curr root)
	Type_of_Expr_Alt type_curr type_next curr next root
	 = Type_Alt (Type_of_Expr (curr root))
	            (Type_of_Expr (next root))

type instance Error_of_Expr ast (Expr_Alt curr next root)
 = Error_of_Expr_Alt ast (curr root) (next root)
-- ** Type family 'Error_of_Expr_Alt'
-- | Remove 'No_Error_Expr' type when building the error of an expression.
type family Error_of_Expr_Alt ast curr next where
	Error_of_Expr_Alt ast No_Error_Expr next = Error_of_Expr ast next
	Error_of_Expr_Alt ast curr No_Error_Expr = Error_of_Expr ast curr
	Error_of_Expr_Alt ast curr next
	 = Error_Expr_Alt (Error_of_Expr ast curr)
	                  (Error_of_Expr ast next)
-- ** Type 'No_Error_Expr'
-- | A discarded error.
data No_Error_Expr
 =   No_Error_Expr
 deriving (Eq, Show)

instance -- Expr_from
 ( Expr_from ast (curr root)
 , Expr_from ast (next root)
 , Root_of_Expr (curr root) ~ root
 , Root_of_Expr (next root) ~ root
 , Error_Expr_Unlift (Error_Expr (Error_of_Type ast (Type_Root_of_Expr root))
                                 (Type_Root_of_Expr root) ast)
                     (Error_of_Expr ast root)
 ) => Expr_from ast (Expr_Alt curr next root) where
	expr_from _ex ctx ast k =
		case expr_from (Proxy::Proxy (curr root)) ctx ast $
		 \ty (Forall_Repr_with_Context repr) ->
			Right $ k ty (Forall_Repr_with_Context repr) of
		 Right ret -> ret
		 Left err ->
			case error_expr_unlift err of
			 Just (Error_Expr_Unsupported_here _
			  :: Error_Expr (Error_of_Type ast (Type_Root_of_Expr root))
			                (Type_Root_of_Expr root) ast) ->
				expr_from (Proxy::Proxy (next root)) ctx ast $
				 \ty (Forall_Repr_with_Context repr) ->
					k ty (Forall_Repr_with_Context repr)
			 _ -> Left err

{- NOTE: useless code so far.
-- ** Type 'Expr_Lift'
-- | Apply 'Peano_of_Expr' on 'Expr_LiftN'.
type Expr_Lift ex exs
 =   Expr_LiftN (Peano_of_Expr ex exs) ex exs

-- | Convenient wrapper around 'expr_liftN',
-- passing it the 'Peano' number from 'Peano_of_Expr'.
expr_lift
 :: forall ex exs (root:: *).
 Expr_Lift ex exs =>
 ex root -> exs root
expr_lift = expr_liftN (Proxy::Proxy (Peano_of_Expr ex exs))

-- *** Type family 'Peano_of_Expr'
-- | Return a 'Peano' number derived from the location
-- of a given expression within a given expression stack,
-- which is used to avoid @OverlappingInstances@.
type family Peano_of_Expr
 (ex::  * -> *)
 (exs:: * -> *) :: * where
	Peano_of_Expr ex    ex                   = Zero
	Peano_of_Expr ex    (Expr_Alt ex   next) = Zero
	Peano_of_Expr other (Expr_Alt curr next) = Succ (Peano_of_Expr other next)

-- *** Class 'Expr_LiftN'
-- | Lift a given expression to the top of a given expression stack including it,
-- by constructing the appropriate sequence of 'Expr_Alt_Curr' and 'Expr_Alt_Next'.
class Expr_LiftN (p:: *) ex exs where
	expr_liftN :: forall (root:: *). Proxy p -> ex root -> exs root
instance Expr_LiftN Zero curr curr where
	expr_liftN _ = id
instance Expr_LiftN Zero curr (Expr_Alt curr next) where
	expr_liftN _ = Expr_Alt_Curr
instance
 Expr_LiftN p other next =>
 Expr_LiftN (Succ p) other (Expr_Alt curr next) where
	expr_liftN _ = Expr_Alt_Next . expr_liftN (Proxy::Proxy p)

-- ** Type 'Expr_Unlift'
-- | Apply 'Peano_of_Expr' on 'Expr_UnliftN'.
type Expr_Unlift ex exs
 =   Expr_UnliftN (Peano_of_Expr ex exs) ex exs

-- | Convenient wrapper around 'expr_unliftN',
-- passing it the 'Peano' number from 'Peano_of_Expr'.
expr_unlift
 :: forall ex exs (root:: *).
 Expr_Unlift ex exs =>
 exs root -> Maybe (ex root)
expr_unlift = expr_unliftN (Proxy::Proxy (Peano_of_Expr ex exs))

-- *** Class 'Expr_UnliftN'
-- | Try to unlift a given expression out of a given expression stack including it,
-- by deconstructing the appropriate sequence of 'Expr_Alt_Curr' and 'Expr_Alt_Next'.
class Expr_UnliftN (p:: *) ex exs where
	expr_unliftN :: forall (root:: *). Proxy p -> exs root -> Maybe (ex root)
instance Expr_UnliftN Zero curr curr where
	expr_unliftN _ = Just
instance Expr_UnliftN Zero curr (Expr_Alt curr next) where
	expr_unliftN _ (Expr_Alt_Curr x) = Just x
	expr_unliftN _ (Expr_Alt_Next _) = Nothing
instance
 Expr_UnliftN p other next =>
 Expr_UnliftN (Succ p) other (Expr_Alt curr next) where
	expr_unliftN _ (Expr_Alt_Next x) = expr_unliftN (Proxy::Proxy p) x
	expr_unliftN _ (Expr_Alt_Curr _) = Nothing
-}

-- ** Type family 'Is_Last_Expr'
-- | Return whether a given expression is the last one in a given expression stack.
--
-- NOTE: each expression parser uses this type family
-- when it encounters unsupported syntax:
-- to know if it is the last expression parser component that will be tried
-- (and thus return 'Error_Expr_Unsupported')
-- or if some other expression parser component shall be tried
-- (and thus return 'Error_Expr_Unsupported_here',
-- which is then handled accordingly by the 'Expr_from' instance of 'Expr_Alt').
type family Is_Last_Expr (ex:: *) (exs:: *) :: Bool where
	Is_Last_Expr ex        ex                        = 'True
	Is_Last_Expr ex        (Expr_Root exs)           = Is_Last_Expr ex (exs (Expr_Root exs))
	Is_Last_Expr (ex root) (Expr_Alt ex   next root) = 'False
	Is_Last_Expr other     (Expr_Alt curr next root) = Is_Last_Expr other (next root)

-- * Type 'Error_Expr_Alt'
-- | Error expression making an alternative between two error expressions.
data Error_Expr_Alt curr next
 =   Error_Expr_Alt_Curr curr
 |   Error_Expr_Alt_Next next
 deriving (Eq, Show)

-- ** Type 'Error_Expr_Lift'
-- | Apply 'Peano_of_Error_Expr' on 'Error_Expr_LiftN'.
type Error_Expr_Lift err errs
 =   Error_Expr_LiftN (Peano_of_Error_Expr err errs) err errs

-- | Convenient wrapper around 'error_expr_liftN',
-- passing it the 'Peano' number from 'Peano_of_Error_Expr'.
error_expr_lift
 :: forall err errs.
 Error_Expr_Lift err errs => err -> errs
error_expr_lift = error_expr_liftN (Proxy::Proxy (Peano_of_Error_Expr err errs))

-- *** Type family 'Peano_of_Error_Expr'
-- | Return a 'Peano' number derived from the location
-- of a given error expression within a given error expression stack,
-- which is used to avoid @OverlappingInstances@.
type family Peano_of_Error_Expr (err:: *) (errs:: *) :: * where
	Peano_of_Error_Expr err   err                        = Zero
	Peano_of_Error_Expr err   (Error_Expr_Alt err  next) = Zero
	Peano_of_Error_Expr other (Error_Expr_Alt curr next) = Succ (Peano_of_Error_Expr other next)

-- *** Class 'Error_Expr_LiftN'
-- | Lift a given expression to the top of a given expression stack including it,
-- by constructing the appropriate sequence of 'Error_Expr_Alt_Curr' and 'Error_Expr_Alt_Next'.
class Error_Expr_LiftN (p:: *) err errs where
	error_expr_liftN :: Proxy p -> err -> errs
instance Error_Expr_LiftN Zero curr curr where
	error_expr_liftN _ = id
instance Error_Expr_LiftN Zero curr (Error_Expr_Alt curr next) where
	error_expr_liftN _ = Error_Expr_Alt_Curr
instance
 Error_Expr_LiftN p other next =>
 Error_Expr_LiftN (Succ p) other (Error_Expr_Alt curr next) where
	error_expr_liftN _ = Error_Expr_Alt_Next . error_expr_liftN (Proxy::Proxy p)

-- ** Type 'Error_Expr_Unlift'
-- | Apply 'Peano_of_Error_Expr' on 'Error_Expr_UnliftN'.
type Error_Expr_Unlift ex exs
 =   Error_Expr_UnliftN (Peano_of_Error_Expr ex exs) ex exs

-- | Convenient wrapper around 'error_expr_unliftN',
-- passing it the 'Peano' number from 'Peano_of_Error_Expr'.
error_expr_unlift
 :: forall ex exs.
 Error_Expr_Unlift ex exs => exs -> Maybe ex
error_expr_unlift = error_expr_unliftN (Proxy::Proxy (Peano_of_Error_Expr ex exs))

-- *** Class 'Error_Expr_UnliftN'
-- | Try to unlift a given expression error out of a given expression error stack including it,
-- by deconstructing the appropriate sequence of 'Error_Expr_Alt_Curr' and 'Error_Expr_Alt_Next'.
class Error_Expr_UnliftN (p:: *) ex exs where
	error_expr_unliftN :: Proxy p -> exs -> Maybe ex
instance Error_Expr_UnliftN Zero curr curr where
	error_expr_unliftN _ = Just
instance Error_Expr_UnliftN Zero curr (Error_Expr_Alt curr next) where
	error_expr_unliftN _ (Error_Expr_Alt_Curr x) = Just x
	error_expr_unliftN _ (Error_Expr_Alt_Next _) = Nothing
instance
 Error_Expr_UnliftN p other next =>
 Error_Expr_UnliftN (Succ p) other (Error_Expr_Alt curr next) where
	error_expr_unliftN _ (Error_Expr_Alt_Next x) = error_expr_unliftN (Proxy::Proxy p) x
	error_expr_unliftN _ (Error_Expr_Alt_Curr _) = Nothing

-- * Type 'Error_Expr_Read'
-- | Common expression errors.
data Error_Expr err_ty ty ast
 =   Error_Expr_Wrong_number_of_arguments ast Int
 -- ^ Wrong number of arguments applied to a term,
 -- the integer is the number of arguments expected.
 |   Error_Expr_Type_mismatch ast (Exists_Type ty) (Exists_Type ty)
 -- ^ Mismatch between respectively expected and actual type.
 |   Error_Expr_Constraint_missing ast {-Exists_Dict-} (Exists_Type ty)
 -- ^ A 'Constraint' is missing.
 |   Error_Expr_Read Error_Read ast
 -- ^ Error when reading a literal.
 |   Error_Expr_Type err_ty ast
 -- ^ Error when parsing a type.
 |   Error_Expr_Unsupported ast
 -- ^ Given syntax is supported by none
 -- of the expression parser components
 -- of the expression stack.
 |   Error_Expr_Unsupported_here ast
 -- ^ Given syntax not supported by
 -- the current expression parser component.
 deriving (Eq, Show)

-- | Convenient wrapper around 'error_expr_lift',
-- passing the type family boilerplate.
error_expr
 :: forall ast ex ty.
 (ty ~ Type_Root_of_Expr ex)
 => Error_Expr_Lift
   (Error_Expr (Error_of_Type ast ty) ty ast)
   (Error_of_Expr ast (Root_of_Expr ex))
 => Proxy ex
 -> Error_Expr (Error_of_Type ast ty) ty ast
 -> Error_of_Expr ast (Root_of_Expr ex)
error_expr _ = error_expr_lift

-- | Utility to return 'Error_Expr_Unsupported'
-- or 'Error_Expr_Unsupported_here'
-- according to the given expression.
error_expr_unsupported
 :: forall ast ex ty root.
 ( root ~ Root_of_Expr ex
 , ty ~ Type_Root_of_Expr ex
 , Implicit_HBool (Is_Last_Expr ex root)
 , Error_Expr_Lift (Error_Expr (Error_of_Type ast ty) ty ast)
                   (Error_of_Expr ast root)
 ) => Proxy ex -> ast
 -> Error_of_Expr ast (Root_of_Expr ex)
error_expr_unsupported ex ast =
	case hbool :: HBool (Is_Last_Expr ex root) of
	 HTrue  -> error_expr ex $ Error_Expr_Unsupported ast
	 HFalse -> error_expr ex $ Error_Expr_Unsupported_here ast

-- | Utility to check that two types are equal
-- or raise 'Error_Expr_Type_mismatch'.
when_type_eq
 :: forall ast ex root ty x y ret.
 ( root ~ Root_of_Expr ex
 , ty ~ Type_Root_of_Expr ex
 , Type_Eq ty
 , Error_Expr_Lift (Error_Expr (Error_of_Type ast ty) ty ast)
                   (Error_of_Expr ast root)
 )
 => Proxy ex -> ast -> ty x -> ty y
 -> (x :~: y -> Either (Error_of_Expr ast root) ret)
 -> Either (Error_of_Expr ast root) ret
when_type_eq ex ast x y k =
	case x `type_eq` y of
	 Just Refl -> k Refl
	 Nothing -> Left $ error_expr ex $
		Error_Expr_Type_mismatch ast
		 (Exists_Type x)
		 (Exists_Type y)

when_type_constraint
 :: forall ast ex c root ty h ret.
 ( root ~ Root_of_Expr ex
 , ty ~ Type_Root_of_Expr ex
 , Error_Expr_Lift (Error_Expr (Error_of_Type ast ty) ty ast)
                   (Error_of_Expr ast root)
 , Type_Constraint c ty
 )
 => Proxy ex -> Proxy c -> ast -> ty h
 -> (Dict (c h) -> Either (Error_of_Expr ast root) ret)
 -> Either (Error_of_Expr ast root) ret
when_type_constraint ex c ast ty k =
	case type_constraint c ty of
	 Just Dict -> k Dict
	 Nothing -> Left $ error_expr ex $
		Error_Expr_Constraint_missing ast
		 {-(Exists_Dict c)-}
		 (Exists_Type ty)

-- * Type 'Error_Read'
-- | Error parsing a host-term.
data Error_Read
 =   Error_Read Text
 deriving (Eq, Show)

-- | Parse a host-term.
read_safe :: Read h => Text -> Either Error_Read h
read_safe t =
	case reads $ Text.unpack t of
	 [(x, "")] -> Right x
	 _         -> Left $ Error_Read t