packages feed

hypertypes-0.2.2: src/Hyper/Infer.hs

{-# LANGUAGE FlexibleContexts #-}

module Hyper.Infer
    ( infer
    , InferResultsConstraint
    , inferUVarsApplyBindings
    , module Hyper.Class.Infer
    , module Hyper.Class.Infer.Env
    , module Hyper.Class.Infer.InferOf
    , module Hyper.Infer.ScopeLevel
    , module Hyper.Infer.Result
      -- | Exported only for SPECIALIZE pragmas
    , inferH
    ) where

import qualified Control.Lens as Lens
import Hyper
import Hyper.Class.Infer
import Hyper.Class.Infer.Env
import Hyper.Class.Infer.InferOf
import Hyper.Class.Nodes (HNodesHaveConstraint (..))
import Hyper.Infer.Result
import Hyper.Infer.ScopeLevel
import Hyper.Unify (UVarOf, Unify, applyBindings)

import Hyper.Internal.Prelude

-- | Perform Hindley-Milner type inference of a term
{-# INLINE infer #-}
infer ::
    forall m t a.
    Infer m t =>
    Ann a # t ->
    m (Ann (a :*: InferResult (UVarOf m)) # t)
infer (Ann a x) =
    inferBody (hmap (Proxy @(Infer m) #> inferH) x)
        <&> (\(xI, t) -> Ann (a :*: InferResult t) xI)
        \\ inferContext (Proxy @m) (Proxy @t)

{-# INLINE inferH #-}
inferH ::
    Infer m t =>
    Ann a # t ->
    InferChild m (Ann (a :*: InferResult (UVarOf m))) # t
inferH c = infer c <&> (\i -> InferredChild i (i ^. hAnn . Lens._2 . _InferResult)) & InferChild

type InferResultsConstraint c = Recursively (InferOfConstraint (HNodesHaveConstraint c))

inferUVarsApplyBindings ::
    forall m t a.
    ( Applicative m
    , RTraversable t
    , Recursively (InferOfConstraint HTraversable) t
    , InferResultsConstraint (Unify m) t
    ) =>
    Ann (a :*: InferResult (UVarOf m)) # t ->
    m (Ann (a :*: InferResult (Pure :*: UVarOf m)) # t)
inferUVarsApplyBindings =
    htraverseFlipped $
        Proxy @(Recursively (InferOfConstraint HTraversable)) #*#
            Proxy @(InferResultsConstraint (Unify m)) #>
                Lens._2 f
    where
        f ::
            forall n.
            ( Recursively (InferOfConstraint HTraversable) n
            , InferResultsConstraint (Unify m) n
            ) =>
            InferResult (UVarOf m) # n ->
            m (InferResult (Pure :*: UVarOf m) # n)
        f =
            htraverseFlipped (Proxy @(Unify m) #> \x -> applyBindings x <&> (:*: x))
                \\ inferOfConstraint @HTraversable (Proxy @n)
                \\ recursively (Proxy @(InferOfConstraint HTraversable n))
                \\ hNodesHaveConstraint (Proxy @(Unify m)) (Proxy @(InferOf n))
                \\ inferOfConstraint @(HNodesHaveConstraint (Unify m)) (Proxy @n)
                \\ recursively (Proxy @(InferOfConstraint (HNodesHaveConstraint (Unify m)) n))