{-# LANGUAGE ScopedTypeVariables, TypeApplications, FlexibleContexts, AllowAmbiguousTypes #-}
module Overload.Normal where

import Control.Effects.State
import Data.Functor.Identity

import Overload.TypeTree

newtype Normal = Normal Int deriving (Eq, Ord)
instance Show Normal where
    show (Normal n) = show n

type FreshSource a = ([(a, Normal)], Normal)

lookupName :: (MonadEffect (State (FreshSource a)) m, Eq a) => a -> m Normal
lookupName name = do
    (table, Normal top) <- getState
    case lookup name table of
        Nothing -> do
            setState ((name, Normal top) : table, Normal (top + 1))
            return (Normal top)
        Just n  -> return n

freshVar :: forall a m. MonadEffect (State (FreshSource a)) m => m Normal
freshVar = do
    (table, Normal top) :: FreshSource a <- getState
    setState (table, Normal (top + 1))
    return (Normal top)

normalizeTypeTree :: forall a. Eq a => TypeTree (Maybe a) -> TypeTree Normal
normalizeTypeTree =
      runIdentity
    . implementStateViaStateT (([], Normal 0) :: FreshSource a)
    . traverse (maybe (freshVar @a) lookupName)