data Common = ...<br>data A = ...<br>data B = ...<br>data C = ...<br>data Super =<br>    SubA { commonFields :: Common, getA :: A }<br>    | SubB { commonFields :: Common, getB :: B }<br>    | SubC { commonFields :: Common, getC :: C }<br>
<br>foldWithSubtype :: (A -&gt; r) -&gt; (B -&gt; r) -&gt; (C -&gt; r) -&gt; Super -&gt; r<br>foldWithSubtype k _ _ (SubA {getA = a}) = k a<br>foldWithSubtype _ k _ (SubB {getB = b}) = k b<br>
foldWithSubtype _ _ k (SubC {getC = c}) = k c<br><br>foldSuper :: (A -&gt; Common -&gt; r) -&gt; (B -&gt; Common -&gt; r) -&gt; (C -&gt; Common -&gt; r) -&gt; Super -&gt; r<br>foldSuper ka kb kc sup = foldWithSubtype ka kb kc sup $ commonFields sup<br>
<br><br><div class="gmail_quote">On Mon, Mar 12, 2012 at 8:32 AM, Jeff Shaw <span dir="ltr">&lt;<a href="mailto:shawjef3@msu.edu">shawjef3@msu.edu</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
More specifically, if I have a record type from which I construct multiple sub-record types, and I want to store these in a collection which I want to map over while preserving the ability to get at the sub-fields, is there a better way to do it than to have an enumeration for the sub-types and then use Dynamic? I also have a nastier version that doesn&#39;t require the enumeration, which throws an exception when fromDynamic can&#39;t return a value with one of the expected types.<br>

<br>
{-# LANGUAGE Rank2Types, DeriveDataTypeable #-}<br>
module Super where<br>
<br>
import Data.Dynamic<br>
import Data.Typeable<br>
import Data.Maybe<br>
<br>
data Super a = Super { commonFields :: (), subFields :: a }<br>
    deriving Typeable<br>
<br>
data SubTypes = SubA | SubB | SubC<br>
<br>
data A = A { aFields :: () }<br>
    deriving Typeable<br>
<br>
data B = B { bFields :: () }<br>
    deriving Typeable<br>
<br>
data C = C { cFields :: () }<br>
    deriving Typeable<br>
<br>
doSomethingWithSubType :: (Super A -&gt; ()) -&gt; (Super B -&gt; ()) -&gt; (Super C -&gt; ()) -&gt; (SubTypes, Dynamic) -&gt; Maybe ()<br>
doSomethingWithSubType a _ _ (SubA, dynamic) = fromDynamic dynamic &gt;&gt;= return . a<br>
doSomethingWithSubType _ b _ (SubB, dynamic) = fromDynamic dynamic &gt;&gt;= return . b<br>
doSomethingWithSubType _ _ c (SubC, dynamic) = fromDynamic dynamic &gt;&gt;= return . c<br>
<br>
doSomethingWithSubType2 :: (Super A -&gt; ()) -&gt; (Super B -&gt; ()) -&gt; (Super C -&gt; ()) -&gt; Dynamic -&gt; ()<br>
doSomethingWithSubType2 a b c dynamic =<br>
    let dynamicAsA = fromDynamic dynamic :: Maybe (Super A)<br>
        dynamicAsB = fromDynamic dynamic :: Maybe (Super B)<br>
        dynamicAsC = fromDynamic dynamic :: Maybe (Super C) in<br>
    head $ catMaybes [ dynamicAsA &gt;&gt;= return . a<br>
                     , dynamicAsB &gt;&gt;= return . b<br>
                     , dynamicAsC &gt;&gt;= return . c]<br>
<br>
<br>
______________________________<u></u>_________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/<u></u>mailman/listinfo/haskell-cafe</a><br>
</blockquote></div><br>