Read the paper "Data types a la carte"[1], and check out the compdata[2] library for an implementation.

The idea is that instead of making a big union type like:

data Answers = SexAnswer | AgeAnswer | etc...

you make

data Sex = M | F | etc

newtype Age = Age Int

and then you construct functions that accept sum types:

ageOrSex :: Age :+: Sex -> m Bool
...

A single type class, called :<: in the paper, handles dispatching from sums the underlying values to sums.


[1]: http://www.cs.ru.nl/~W.Swierstra/Publications/DataTypesALaCarte.pdf
[2: https://hackage.haskell.org/package/compdata

On Fri, May 15, 2015 at 5:39 AM, Cody Goodman <codygman.consulting@gmail.com> wrote:
Tom, I'm trying to make a well-typed API to Question/Answers on
medical forms. The questions will be lined with a specific code, so I
want to enforce that certain codes can only contain certain types of
answers.

Andras, thanks. I'll give that a try later today and let you know how it works.

On Fri, May 15, 2015 at 4:12 AM, Andras Slemmer <0slemi0@gmail.com> wrote:
> You can do this, although you still need a datastructure that allows you to
> use the contained type:
>
> {-# LANGUAGE GADTs #-}
> {-# LANGUAGE StandaloneDeriving #-}
> {-# LANGUAGE TypeSynonymInstances #-}
> module Tutorial where
>
> data Gender = Male | Female deriving (Show)
>
> data Race = White | Black deriving (Show)
>
> type Age = Int
>
> data Answer a where
>   Answer :: RacistAgistSexist a => a -> Answer a
>
> deriving instance Show w => Show (Answer w)
>
> data GenderRaceAge
>   = Gender Gender
>   | Race Race
>   | Age Age
>
> class RacistAgistSexist a where
>   genderRaceAge :: a -> GenderRaceAge
> instance RacistAgistSexist Gender where
>   genderRaceAge = Gender
> instance RacistAgistSexist Race where
>   genderRaceAge = Race
> instance RacistAgistSexist Age where
>   genderRaceAge = Age
>
> -- You can use genderRaceAge to get a GenderRaceAge out of the contained
> type if you don't know 'a'
>
>
> On 15 May 2015 at 08:51, Tom Ellis
> <tom-lists-haskell-cafe-2013@jaguarpaw.co.uk> wrote:
>>
>> On Fri, May 15, 2015 at 01:47:49AM -0500, Cody Goodman wrote:
>> > How can I create Answers of type Gender, Race, or Age?
>> >
>> > These should be possible:
>> >
>> > λ> Answer Male
>> > λ> Answer White
>> > λ> Answer Black
>> > λ> Answer 28
>> >
>> > Others such as using a string should not be possible:
>> >
>> > λ> Answer "a string" -- should throw type error
>>
>> It would probably help if you tell us why precisely you want this, and in
>> particular why
>>
>> data Answer = AnswerGender Gender
>>             | AnswerRace   Race
>>             | AnswerAge    Int
>>
>> is not satisfactory.
>>
>> Tom
>>
>> _______________________________________________
>> Haskell-Cafe mailing list
>> Haskell-Cafe@haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe