[Haskell-beginners] data design for a questionnaire (retitled + update)
Alia
alia_khouri at yahoo.com
Wed Nov 23 12:07:20 CET 2011
Hi folks,
As a follow-on question from my prior post, I got stuck on not being able to compile the following
code in my survey data model which basically generally unwraps the the inner type from the
wrapper:
extract :: Question' -> Question a
extract q = case q of
QuestionS x -> extractQString q
QuestionI x -> extractQInt q
QuestionD x -> extractQDouble q
and I had to produce the following instead:
extractQString :: Question' -> Question String
extractQString (QuestionS q) = q
extractQInt :: Question' -> Question Int
extractQInt (QuestionI q) = q
extractQDouble :: Question' -> Question Double
extractQDouble (QuestionD q) = q
An exchange in stackoverflow seems to suggest that the only way to do it is to use GADTs (which is a language extension).
http://stackoverflow.com/questions/6047522/haskell-type-and-pattern-matching-question-extracting-fields-from-a-data-type
I'm disinclined to use language extensions because I'd rather use haskell98 proper to begin with. So Is this indeed the case?
My code has become more verbose as a result and I am trying to learn most elegant and general haskell 'way' (if it exists)
and hence I would appreciate any advice to this end.
regards,
Alia
<survey.hs>
module Main where
import Text.Show.Functions
import Data.Maybe
type Name = String
type QuestionText = String
type Answer = String
type Score = Double
type CorrectAnswer a = a
type Option a = (String, a)
-- type converters
str = id
int s = read s :: Int
double s = read s :: Double
data QuestionType = Open
| Test
| Choice
deriving (Show, Eq)
data Question a = Question
{ questionName :: Name
, questionText :: QuestionText
, questionType :: QuestionType
, answerFunc :: (String -> a)
, correctAnswer :: Maybe a
, options :: Maybe [Option a]
} deriving (Show)
data Question' = QuestionS (Question String)
| QuestionI (Question Int)
| QuestionD (Question Double)
deriving (Show)
data QuestionSet = QuestionSet
{ qsetTitle :: String
, qsetQuestions :: [Question']
, qsetPoints :: Double
} deriving (Show)
data Survey = Survey
{ surveyTitle :: String
, surveyQuestionSets :: [QuestionSet]
} deriving (Show)
parse :: Question a -> Answer -> a
parse = answerFunc
view :: Question a -> String
view q = questionName q
ask :: Question a -> IO ()
ask q = putStrLn $ questionText q
store :: Question a -> Answer -> IO ()
store q ans = putStrLn $ questionName q ++ ": " ++ show ans
{-
extract :: Question' -> Question a
extract q = case q of
QuestionS x -> extractQString q
QuestionI x -> extractQInt q
QuestionD x -> extractQDouble q
-}
extractQString :: Question' -> Question String
extractQString (QuestionS q) = q
extractQInt :: Question' -> Question Int
extractQInt (QuestionI q) = q
extractQDouble :: Question' -> Question Double
extractQDouble (QuestionD q) = q
testQ :: (Eq a) => Question a -> Answer -> Bool
testQ q ans = case (correctAnswer q) of
Nothing -> False
Just x -> x == (answerFunc q $ ans)
testQ' :: Question' -> Answer -> Bool
testQ' q a = case q of
QuestionS x -> testQS q a
QuestionI x -> testQI q a
QuestionD x -> testQD q a
where
testQS q a = testQ (extractQString q) a
testQI q a = testQ (extractQInt q) a
testQD q a = testQ (extractQDouble q) a
testQset :: QuestionSet -> [Answer] -> [Bool]
testQset qs as = zipWith testQ' (qsetQuestions qs) as
evalQset :: QuestionSet -> [Answer] -> Score
evalQset qs as = (total_correct / total_questions) * score
where
total_questions = fromIntegral (length $ qsetQuestions qset)
total_correct = fromIntegral (length $ filter (== True) (testQset qset as))
score = qsetPoints qset
q1 = Question
{ questionName = "q1"
, questionText = "What is our name?"
, questionType = Open
, answerFunc = id
, correctAnswer = Nothing
, options = Nothing
}
q2 = Question
{ questionName = "q2"
, questionText = "What is 1+1?"
, questionType = Test
, answerFunc = int
, correctAnswer = Just 2
, options = Nothing
}
q3 = Question
{ questionName = "q3"
, questionText = "What is 2+1?"
, questionType = Choice
, answerFunc = int
, correctAnswer = Just 3
, options = Just [("a", 2), ("b", 3), ("c", 4)]
}
q4 = Question
{ questionName = "q4"
, questionText = "What is 2.0 + 1.5 ?"
, questionType = Choice
, answerFunc = double
, correctAnswer = Just 3.5
, options = Just [("a", 2.1), ("b", 3.5), ("c", 4.4)]
}
qset = QuestionSet
{ qsetTitle = "simple questions"
, qsetQuestions = [ QuestionS q1
, QuestionI q2
, QuestionI q3
, QuestionD q4
]
, qsetPoints = 100.0
}
survey = Survey
{ surveyTitle = "a survey"
, surveyQuestionSets = [qset]
}
t1 = evalQset qset ["1", "2", "3", "4"]
</survey.hs>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20111123/e78cb9e8/attachment.htm>
More information about the Beginners
mailing list