palik
palik

Reputation: 2853

Class Instance Implementation

Apart from instance IsPerson (EmployeeRecord a) the whole code is a part of the post General Functions with Typeclasses.

ghci compiles the code, but printPerson doesn't print anything. I guess it calls itself recursively.

Main> :l type-class.hs 
[1 of 1] Compiling Main             ( type-class.hs, interpreted )
Ok, modules loaded: Main.
*Main> printPerson $ EmployeeRecord (Student "me" 123) 11

Removing of instance IsPerson (EmployeeRecord a) leads to the exception

Main> printPerson $ EmployeeRecord (Student "me" 123) 11

<interactive>:116:1: error:
    * No instance for (IsPerson (EmployeeRecord Student))
        arising from a use of `printPerson'
    * In the expression:
        printPerson $ EmployeeRecord (Student "me" 123) 11
      In an equation for `it':
          it = printPerson $ EmployeeRecord (Student "me" 123) 11

How should instance IsPerson EmployeeRecord be implemented solve the issue with printPerson?

data Student = Student String Int deriving Show

data Teacher = Teacher
  { teacherName:: String
  , teacherAge:: Int
  , teacherDepartment :: String
  , teacherSalary :: Int
  } deriving Show

class IsPerson a where
  personName :: a -> String
  personAge :: a -> Int

instance IsPerson Student where
  personName (Student n _) = n
  personAge (Student _ a) = a

instance IsPerson Teacher where
  personName = teacherName
  personAge  = teacherAge

data (IsPerson a) => EmployeeRecord a = EmployeeRecord
  {
      employe :: a
    , tenure :: Int
  } deriving (Show)


instance IsPerson (EmployeeRecord a) where
  personName a = personName a
  personAge = undefined

printPerson :: (IsPerson a) => a -> IO ()
printPerson p = putStrLn $ personName p

Upvotes: 0

Views: 72

Answers (1)

castletheperson
castletheperson

Reputation: 33466

Your EmployeeRecord type is like a "box" where the type implementing IsPerson is inside. You need to "unbox" the EmployeeRecord in order to access the "inner" personName.

You can do this unboxing by either pattern matching or using the employe function.

instance IsPerson (EmployeeRecord a) where
  personName (EmployeeRecord a _) = personName a
  personAge (EmployeeRecord a _) = personAge a
instance IsPerson (EmployeeRecord a) where
  personName = personName . employe
  personAge = personAge . employe

By the way, your code makes use of the deprecated DatatypeContexts language extension. Rather than put the constraint on a in the EmployeeRecord type declaration, put the constraint in your instance declaration:

instance IsPerson a => IsPerson (EmployeeRecord a) where

Upvotes: 4

Related Questions