packages feed

lol-typing-1.20160822: Language/LOL/Typing/Solver/Common.hs

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -fno-warn-tabs #-}
module Language.LOL.Typing.Solver.Common where

import Control.Monad (Monad(..))
import Data.Bool
import Data.Eq (Eq(..))
import Data.Functor (Functor(..))
import Data.Monoid ((<>))
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Text.Buildable (Buildable(..))
import Text.Show (Show(..))

-- * Class 'Information'

-- | An associated type constructor
-- to attach informations to a 'Constraint'
-- about why it exists.
--
-- NOTE: an 'Information' should be enough to construct
-- an error message if the 'Constraint' it is associated with
-- leads to an inconsistency.
class (Monad m, Buildable (Info m)) => Information m where
	type Info m

-- ** Class 'Infoable'
class Infoable a info where
	info_insert :: a -> info -> info

-- | A data type constructor to gather informations
-- from the 'Monad' stack of a solver.
-- data family Info (m :: * -> *)

-- ** Type 'Infoed'

-- | A data type to associate some @info@ to a value.
data Infoed info a
 =   Infoed
 {   information :: info
 ,   infoed :: a
 } deriving (Eq, Functor, Show)
instance (Buildable info, Buildable a) => Buildable (Infoed info a) where
	build Infoed { information, infoed } =
		build infoed <> " {- " <> build information <> " -}"

-- * Type 'Error'

-- | A data type constructor to gather errors
-- from the 'Monad' stack of a solver.
data family Error (m :: * -> *)

-- * Type 'Solver_Logable'

class Solver_Logable a m where
	log :: a -> m ()

-- * Class 'State'

class State st where
	state_name    :: st -> Text
	state_options :: st -> [Text]
	state_collect :: st -> [(Text, Text)]
	state_show    :: st -> Text
	
	-- state_show       = Text.pack . show
	state_options _  = []
	state_collect st = [(state_name st, state_show st)]

-- * Type 'Option'

data Option a
 =   Option
 {   option_current :: a
 ,   option_default :: a
 ,   option_description :: Text
 }

instance (Show a, Eq a) => Show (Option a) where
	show a =
		Text.unpack (option_description a)
		 <> ": "
		 <> show (option_current a)
		 <> show_default
		where
		show_default | option_current a == option_default a = " (default)"
		             | otherwise = ""
instance (Buildable a, Eq a) => Buildable (Option a) where
	build a =
		build (option_description a)
		 <> ": "
		 <> build (option_current a)
		 <> build_default
		where
		build_default | option_current a == option_default a = " (default)"
		              | otherwise = ""
instance Functor Option where
	fmap f a =
		a{ option_default = f (option_default a)
		 , option_current = f (option_current a) }

option :: a -> Text -> Option a
option a s =
	Option
	 { option_default     = a
	 , option_current     = a
	 , option_description = s
	 }