packages feed

hydra-kernel-0.17.0: src/main/haskell/Hydra/Overlay/Haskell/AsTerm.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}

-- | Type class for implicit coercion to TypedTerm
-- This allows TypedTerm, TypedBinding, and String to be used where a TypedTerm is expected,
-- while preserving phantom type information.

module Hydra.Overlay.Haskell.AsTerm where

import Hydra.Core
import Hydra.Packaging
import Hydra.Typed


-- | Type class for implicit coercion to TypedTerm, preserving phantom types
-- TypedTerm passes through unchanged, TypedBinding becomes a variable reference
-- The functional dependency ensures that the input type determines the phantom type
class AsTerm f a | f -> a where
  asTerm :: f -> TypedTerm a

instance AsTerm (TypedTerm a) a where
  asTerm = id

instance AsTerm (TypedBinding a) a where
  asTerm (TypedBinding name _) = TypedTerm (TermVariable name)

instance AsTerm (TypedTermDefinition a) a where
  asTerm (TypedTermDefinition name _) = TypedTerm (TermVariable name)

instance AsTerm String String where
  asTerm s = TypedTerm $ TermLiteral $ LiteralString s

instance AsTerm Int Int where
  asTerm i = TypedTerm $ TermLiteral $ LiteralInteger $ IntegerValueInt32 i


-- | Type class for types from which a kernel-level 'Name' can be statically extracted.
-- Used by Phantoms primitives like 'inject', 'match', 'project', 'record', 'unwrap', 'wrap'
-- to accept either a bare 'Name' or any name-typed binding/definition where the 'Name'
-- is known at construction time. Distinct from 'AsTerm' (which can lift arbitrary
-- @TypedTerm Name@ values, but those don't yield a static 'Name').
class AsName n where
  asName :: n -> Name

instance AsName Name where
  asName = id

instance AsName (TypedBinding Name) where
  asName (TypedBinding name _) = name

instance AsName (TypedTermDefinition Name) where
  asName (TypedTermDefinition name _) = name