packages feed

overloaded-0.3.1: src/Overloaded/Constructors.hs

{-# LANGUAGE AllowAmbiguousTypes    #-}
{-# LANGUAGE DataKinds              #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE PolyKinds              #-}
{-# LANGUAGE TypeFamilies           #-}
{-# LANGUAGE TypeOperators          #-}
{-# LANGUAGE UndecidableInstances   #-}
module Overloaded.Constructors where

import Data.Kind (Type)

-- | Class for the overloaded constructors.
--
-- Instances for this class are automatically generated by type-checker
-- plugin, but you may also defined your own. See an example instances for 'Either'.
--
-- @
-- {-\# OPTIONS -fplugin=Overloaded -fplugin-opt=Overloaded:Constructors #-}
-- @
--
-- Additionally, this overload steals syntax transforming all
-- @(:name arg1 arg2)@ into @'build' \@"name" (arg1, arg2)@ expressions.
-- Parenthesis are important as standalone @:name@ is (for now) not valid
-- Haskell syntax and they also naturally delimit the arguments.
--
-- For nullary constructors the @a@ type is unit @()@,
-- for unary the type is used as is,
-- and for others the parameters are wrapped into a tuple.
-- The last case is not particularly pretty, but its overloadable.
--
--
class HasConstructor x (s :: Type) (a :: Type) | x s -> a where
    build :: a -> s
    match :: s -> Maybe a

-------------------------------------------------------------------------------
-- An example
-------------------------------------------------------------------------------

instance a' ~ a => HasConstructor "Left" (Either a b) a' where
    build = Left
    match = \s -> case s of
        Left a  -> Just a
        Right _ -> Nothing

instance a' ~ b => HasConstructor "Right" (Either a b) a' where
    build = Right
    match = \s -> case s of
        Left _  -> Nothing
        Right b -> Just b