module Syntax.Basic.Typeclass.RequiredTypeClasses where
import Prelude
{-
Type classes can also have relationships with other type classes.
While the syntax looks hierarchial (i.e. parent-child relationships),
they aren't necessarily hierarchical. Rather, one should see them as
"conditional," which will be shown soon.
-}
-- Here's the syntax. It reads,
-- "Type 'a' can have an instance of the type class,
-- 'ActualTypeClass.' However, it must also have an instance
-- of the type class, 'RequiredTypeClass.'"
class RequiredTypeClass a <= ActualTypeClass a where
functionName :: a -> ReturnType
-- examples
-- the required type class of 'PlusFive'
class ToInt a where
toInt :: a -> Int
class ToInt a <= PlusFive a where
plusFive :: a -> Int
-- Writing an instance of ActualTypeClass does not require a constraint
-- from RequiredTypeClass in its type signature as this is already known due
-- to `ActualTypeClass`'s definition
instance ActualTypeClass TheType where
functionName _ = "body"
-- example
instance ToInt Boolean where
toInt true = 1
toInt false = 0
instance PlusFive Boolean where
plusFive b = 5 + toInt b
-- using it in code
test1 :: Boolean
test1 = (plusFive true) == 6
test2 :: Boolean
test2 = (plusFive false) == 5
-- Now let's explain what we mean by "conditional."
instance ToInt Int where
-- notice how the required type class, `ToInt`, is using functions
-- from its extension type class, `PlusFive`.
toInt x = plusFive x
instance PlusFive Int where
plusFive b = 5 + b
-- If a type implements instances for a number of type classes, its instances
-- can use any of these type class' functions/values. Still,
-- one of those instances will actually need to be independent from the
-- others (i.e. it doesn't use any functions/values from other type classes).
-- A type class can also combine multiple typeclasses. Sometimes,
-- they will add additional functionality or laws. Other times,
-- they simply combine two or more type classes into one.
class RequiredTypeClass1 a where
fn1 :: a -> String
class RequiredTypeClass2 a where
fn2 :: a -> String
-- Example of combining and adding additional functionality:
class (RequiredTypeClass1 a, RequiredTypeClass2 a {-, ... -}) <= TheTypeClass a where
function :: a -> a
-- Example of only combining and not adding any additional functionality.
-- Sometimes, this will add another law; other times, it only combines
-- multiple type classes together:
class (RequiredTypeClass1 a, RequiredTypeClass2 a {-, ... -}) <= CombineOnly a
-- necessary to make file compile
type ReturnType = String
data TheType = TheType
class RequiredTypeClass a where
fn :: a -> String
instance RequiredTypeClass TheType where
fn _ = "body"