packages feed

disco-0.1.0.0: src/Disco/Types/Qualifiers.hs

{-# LANGUAGE DeriveAnyClass    #-}
{-# LANGUAGE OverloadedStrings #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Disco.Types.Qualifiers
-- Copyright   :  disco team and contributors
-- Maintainer  :  byorgey@gmail.com
--
-- Type qualifiers and sorts.
--
-----------------------------------------------------------------------------

-- SPDX-License-Identifier: BSD-3-Clause

module Disco.Types.Qualifiers where

import           GHC.Generics
import           Unbound.Generics.LocallyNameless

import           Data.Set                         (Set)
import qualified Data.Set                         as S

import           Disco.Pretty
import           Disco.Syntax.Operators

------------------------------------------------------------
-- Qualifiers
------------------------------------------------------------

-- | A "qualifier" is kind of like a type class in Haskell; but unlike
--   Haskell, disco users cannot define their own.  Rather, there is a
--   finite fixed list of qualifiers supported by disco.  For example,
--   @QSub@ denotes types which support a subtraction operation.  Each
--   qualifier corresponds to a set of types which satisfy it (see
--   'hasQual' and 'qualRules').
--
--   These qualifiers generally arise from uses of various operations.
--   For example, the expression @\\x y. x - y@ would be inferred to
--   have a type @a -> a -> a [subtractive a]@, that is, a function of
--   type @a -> a -> a@ where @a@ is any type that supports
--   subtraction.
--
--   These qualifiers can appear in a 'CQual' constraint; see
--   "Disco.Typecheck.Constraint".
data Qualifier
  = QNum       -- ^ Numeric, i.e. a semiring supporting + and *
  | QSub       -- ^ Subtractive, i.e. supports -
  | QDiv       -- ^ Divisive, i.e. supports /
  | QCmp       -- ^ Comparable, i.e. supports decidable ordering/comparison (see Note [QCmp])
  | QEnum      -- ^ Enumerable, i.e. supports ellipsis notation [x .. y]
  | QBool      -- ^ Boolean, i.e. supports and, or, not (Bool or Prop)
  | QBasic     -- ^ Things that do not involve Prop.
  | QSimple    -- ^ Things for which we can derive a *Haskell* Ord instance
  deriving (Show, Eq, Ord, Generic, Alpha)

instance Pretty Qualifier where
  pretty = \case
    QNum    -> "num"
    QSub    -> "sub"
    QDiv    -> "div"
    QCmp    -> "cmp"
    QEnum   -> "enum"
    QBool   -> "bool"
    QBasic  -> "basic"
    QSimple -> "simple"

-- ~~~~ Note [QCmp]
--
-- XXX edit this!  I don't think we actually need type info for
-- comparisons at runtime any more, if we disallow functions from
-- being QCmp.  With the switch to eager semantics + disallowing
-- function comparison, it's now the case that QCmp should mean
-- *decidable* (terminating) comparison.
--
-- It used to be the case that every type in disco supported
-- (semi-decidable) linear ordering, so in one sense the QCmp
-- constraint was unnecessary.  However, in order to do a comparison we
-- need to know the type at runtime.  Currently, we use QCmp to track
-- which types have comparisons done on them, and reject any type
-- variables with a QCmp constraint (just as we reject any other type
-- variables with remaining constraints).  Every type with comparisons
-- done on it must be statically known at compile time.
--
-- However, there's now another reason: the Prop type does not support
-- comparisons at all.
--
-- Eventually, one could imagine compiling to something like System F
-- with explicit type lambdas and applications; then the QCmp
-- constraints would tell us which type applications need to be kept
-- and which can be erased.

-- | A helper function that returns the appropriate qualifier for a
--   binary arithmetic operation.
bopQual :: BOp -> Qualifier
bopQual Add  = QNum
bopQual Mul  = QNum
bopQual Div  = QDiv
bopQual Sub  = QSub
bopQual SSub = QNum
-- bopQual And  = QBool
-- bopQual Or   = QBool
-- bopQual Impl = QBool
bopQual _    = error "No qualifier for binary operation"

------------------------------------------------------------
-- Sorts
------------------------------------------------------------

-- | A 'Sort' represents a set of qualifiers, and also represents a
--   set of types (in general, the intersection of the sets
--   corresponding to the qualifiers).
type Sort = Set Qualifier

-- | The special sort \(\top\) which includes all types.
topSort :: Sort
topSort = S.empty