{"id":401,"date":"2022-08-30T15:00:44","date_gmt":"2022-08-30T15:00:44","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2013\/11\/09\/generate-the-list-of-ints-associated-with-an-enum-type-collection-of-common-programming-errors\/"},"modified":"2022-08-30T15:00:44","modified_gmt":"2022-08-30T15:00:44","slug":"generate-the-list-of-ints-associated-with-an-enum-type-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2022\/08\/30\/generate-the-list-of-ints-associated-with-an-enum-type-collection-of-common-programming-errors\/","title":{"rendered":"Generate the list of Ints associated with an Enum type-Collection of common programming errors"},"content":{"rendered":"<p>I have a utility function that enumerates all values of a type that is both enumerable and bounded:<\/p>\n<pre><code>enumerate :: (Enum a, Bounded a) =&gt; [a]\nenumerate = [minBound .. maxBound]\n<\/code><\/pre>\n<p>and a data type that involves mapping enumerable types to integers:<\/p>\n<pre><code>data Attribute a = Attribute { test :: a -&gt; Int\n                             , vals :: [Int]\n                             , name :: String }\n<\/code><\/pre>\n<p>Where <code>vals<\/code> is the list of integers representing all possible enumerable values. For example, if I had<\/p>\n<pre><code>data Foo = Zero | One | Two deriving (Enum,Bounded)\n<\/code><\/pre>\n<p>then <code>vals<\/code> would be <code>[0,1,2]<\/code>.<\/p>\n<p>I want to be able to create these attributes programatically, just given a function that maps an <code>a<\/code> to an enumerable type, and a name. Something like this:<\/p>\n<pre><code>attribute :: (Enum b, Bounded b) =&gt; (a -&gt; b) -&gt; String -&gt; Attribute a\nattribute f str = Attribute (fromEnum . f) vs str\n  where\n    vs = map fromEnum enumerate\n<\/code><\/pre>\n<p>This doesn&#8217;t typecheck, because there&#8217;s no way of connecting the call to <code>enumerate<\/code> with the <code>b<\/code> in the type signature. So I thought I could do this:<\/p>\n<pre><code>vs = map fromEnum $ enumerate :: [b]\n<\/code><\/pre>\n<p>but that doesn&#8217;t compile either &#8211; the compiler renames that <code>b<\/code> to <code>b1<\/code>. I tried to be smarter, using the GADTs extension:<\/p>\n<pre><code>attribute :: (Enum b, Bounded b, b ~ c) =&gt; {- ... -}\nvs = map fromEnum $ enumerate :: (Enum c,Bounded c) =&gt; [c]\n<\/code><\/pre>\n<p>but again, the <code>c<\/code> is renamed to <code>c1<\/code>.<\/p>\n<p>I don&#8217;t want to include the type of <code>b<\/code> as a parameter in the <code>Attribute<\/code> type (mainly because I want to store lists of attributes with potentially different values of <code>b<\/code> &#8211; that&#8217;s why <code>test<\/code> has type <code>a -&gt; Int<\/code> and <code>vals<\/code> has type <code>[Int]<\/code>).<\/p>\n<p>How can I write this code so that it does what I want it to do?<\/p>\n<ol>\n<li>\n<p>The problem with type variables is that they are only bound in the type signature. Any use of type variables inside definition will refer to new, fresh type variable (even though it has the exact same name as in the type signature).<\/p>\n<p>There are two ways to refer to type variables from signature: <code>ScopedTypeVariables<\/code> extension and <code>asTypeOf<\/code>.<\/p>\n<p>With <code>ScopedTypeVariables<\/code> a type variable explicitly bound with <code>forall<\/code> is also available in definition, thus:<\/p>\n<pre><code>attribute :: forall a b. (Enum b, Bounded b) =&gt;\n             (a -&gt; b) -&gt; String -&gt; Attribute a\nattribute f str = Attribute (fromEnum . f) vs str\n  where\n    vs = map fromEnum (enumerate :: [b])\n<\/code><\/pre>\n<p>The other way involves function <code>asTypeOf<\/code> defined as:<\/p>\n<pre><code>asTypeOf :: a -&gt; a -&gt; a\nasTypeOf = const\n<\/code><\/pre>\n<p>If we can get an expression of type <code>[b]<\/code> into the second parameter, unification will make sure that first parameter also has type <code>[b]<\/code>. Because we have <code>f :: a -&gt; b<\/code> and <code>f undefined :: b<\/code>, we can write:<\/p>\n<pre><code>attribute :: (Enum b, Bounded b) =&gt; (a -&gt; b) -&gt; String -&gt; Attribute a\nattribute f str = Attribute (fromEnum . f) vs str\n  where\n    vs = map fromEnum (enumerate `asTypeOf` [f undefined])\n<\/code><\/pre>\n<\/li>\n<\/ol>\n<p id=\"rop\"><small>Originally posted 2013-11-09 19:01:36. <\/small><\/p>","protected":false},"excerpt":{"rendered":"<p>I have a utility function that enumerates all values of a type that is both enumerable and bounded: enumerate :: (Enum a, Bounded a) =&gt; [a] enumerate = [minBound .. maxBound] and a data type that involves mapping enumerable types to integers: data Attribute a = Attribute { test :: a -&gt; Int , vals [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-401","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/401","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=401"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/401\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=401"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=401"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=401"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}