<div dir="ltr"><div>Read the paper "Data types a la carte"[1], and check out the compdata[2] library for an implementation.<br></div><div><br></div><div>The idea is that instead of making a big union type like:</div><div><br></div><div>data Answers = SexAnswer | AgeAnswer | etc...</div><div><br></div><div>you make</div><div><br></div><div>data Sex = M | F | etc</div><div><br></div><div>newtype Age = Age Int</div><div><br></div><div>and then you construct functions that accept sum types:</div><div><br></div><div>ageOrSex :: Age :+: Sex -> m Bool</div><div>...</div><div><br></div><div>A single type class, called :<: in the paper, handles dispatching from sums the underlying values to sums.</div><div><br></div><div><br></div><div>[1]: <a href="http://www.cs.ru.nl/~W.Swierstra/Publications/DataTypesALaCarte.pdf">http://www.cs.ru.nl/~W.Swierstra/Publications/DataTypesALaCarte.pdf</a><br></div><div>[2: <a href="https://hackage.haskell.org/package/compdata">https://hackage.haskell.org/package/compdata</a><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, May 15, 2015 at 5:39 AM, Cody Goodman <span dir="ltr"><<a href="mailto:codygman.consulting@gmail.com" target="_blank">codygman.consulting@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Tom, I'm trying to make a well-typed API to Question/Answers on<br>
medical forms. The questions will be lined with a specific code, so I<br>
want to enforce that certain codes can only contain certain types of<br>
answers.<br>
<br>
Andras, thanks. I'll give that a try later today and let you know how it works.<br>
<div class="HOEnZb"><div class="h5"><br>
On Fri, May 15, 2015 at 4:12 AM, Andras Slemmer <<a href="mailto:0slemi0@gmail.com">0slemi0@gmail.com</a>> wrote:<br>
> You can do this, although you still need a datastructure that allows you to<br>
> use the contained type:<br>
><br>
> {-# LANGUAGE GADTs #-}<br>
> {-# LANGUAGE StandaloneDeriving #-}<br>
> {-# LANGUAGE TypeSynonymInstances #-}<br>
> module Tutorial where<br>
><br>
> data Gender = Male | Female deriving (Show)<br>
><br>
> data Race = White | Black deriving (Show)<br>
><br>
> type Age = Int<br>
><br>
> data Answer a where<br>
>   Answer :: RacistAgistSexist a => a -> Answer a<br>
><br>
> deriving instance Show w => Show (Answer w)<br>
><br>
> data GenderRaceAge<br>
>   = Gender Gender<br>
>   | Race Race<br>
>   | Age Age<br>
><br>
> class RacistAgistSexist a where<br>
>   genderRaceAge :: a -> GenderRaceAge<br>
> instance RacistAgistSexist Gender where<br>
>   genderRaceAge = Gender<br>
> instance RacistAgistSexist Race where<br>
>   genderRaceAge = Race<br>
> instance RacistAgistSexist Age where<br>
>   genderRaceAge = Age<br>
><br>
> -- You can use genderRaceAge to get a GenderRaceAge out of the contained<br>
> type if you don't know 'a'<br>
><br>
><br>
> On 15 May 2015 at 08:51, Tom Ellis<br>
> <<a href="mailto:tom-lists-haskell-cafe-2013@jaguarpaw.co.uk">tom-lists-haskell-cafe-2013@jaguarpaw.co.uk</a>> wrote:<br>
>><br>
>> On Fri, May 15, 2015 at 01:47:49AM -0500, Cody Goodman wrote:<br>
>> > How can I create Answers of type Gender, Race, or Age?<br>
>> ><br>
>> > These should be possible:<br>
>> ><br>
>> > λ> Answer Male<br>
>> > λ> Answer White<br>
>> > λ> Answer Black<br>
>> > λ> Answer 28<br>
>> ><br>
>> > Others such as using a string should not be possible:<br>
>> ><br>
>> > λ> Answer "a string" -- should throw type error<br>
>><br>
>> It would probably help if you tell us why precisely you want this, and in<br>
>> particular why<br>
>><br>
>> data Answer = AnswerGender Gender<br>
>>             | AnswerRace   Race<br>
>>             | AnswerAge    Int<br>
>><br>
>> is not satisfactory.<br>
>><br>
>> Tom<br>
>><br>
>> _______________________________________________<br>
>> Haskell-Cafe mailing list<br>
>> <a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
>> <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
><br>
><br>
><br>
> _______________________________________________<br>
> Haskell-Cafe mailing list<br>
> <a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
> <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
><br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
</div></div></blockquote></div><br></div></div>