Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>This is something that's easy to get wrong.</p> <p>What you have in the signature of <code>optimize</code> is <em>not</em> an existential, but a universal.</p> <p>...since existentials are somewhat outdated anyway, let's rewrite your data to GADT form, which makes the point clearer as the syntax is essentially the same as for polymorphic functions:</p> <pre><code>data Container a where (:/-&gt;) :: Ord v =&gt; -- come on, you can't call this `Cons`! OptiF a v -&gt; (a-&gt;Int) -&gt; Container a </code></pre> <p>Observe that the <code>Ord</code> constraint (which implies that here's the <code>forall v...</code>) stands outside of the type-variable–parameterised function signature, i.e. <em><code>v</code> is a parameter we can dictate from the outside when we want to construct a <code>Container</code> value</em>. In other words,</p> <blockquote> <p>For all <code>v</code> in <code>Ord</code> <strong>there exists</strong> the constructor <code>(:/-&gt;) :: OptiF a v -&gt; (a-&gt;Int) -&gt; Container a</code></p> </blockquote> <p>which is what gives rise to the name "existential type". Again, this is analog to an ordinary polymorphic function.</p> <p>On the other hand, in the signature</p> <pre><code>optimize :: (forall v. (Ord v) =&gt; a -&gt; v) -&gt; Container a -&gt; Int </code></pre> <p>you have a <code>forall</code> inside the signature term itself, which means that what concrete type <code>v</code> may take on will be determined by the <em>callee</em>, <code>optimize</code>, internally – all we have control over from the outside is that it be in <code>Ord</code>. Nothing "existential" about that, which is why this signature won't actually compile with <code>XExistentialQuantification</code> or <code>XGADTs</code> alone:</p> <pre><code>&lt;interactive&gt;:37:26: Illegal symbol '.' in type Perhaps you intended -XRankNTypes or similar flag to enable explicit-forall syntax: forall &lt;tvs&gt;. &lt;type&gt; </code></pre> <p><code>val = (*3)</code> obviously doesn't fulfill <code>(forall v. (Ord v) =&gt; a -&gt; v)</code>, it actually requires a <code>Num</code> instance which not all <code>Ord</code>s have. Indeed, <code>optimize</code> shouldn't need the rank2 type: it should work for any <code>Ord</code>-type <code>v</code> the caller might give to it.</p> <pre><code>optimize :: Ord v =&gt; (a -&gt; v) -&gt; Container a -&gt; Int </code></pre> <p>in which case your implementation doesn't work anymore, though: since <code>(:/-&gt;)</code> is really an existential constructor, it needs to contain only <em>any</em> <code>OptiF</code> function, for <em>some</em> unknown type <code>v1</code>. So the caller of optimize has the freedom to choose the opti-function for any particular such type, and the function to be optimised for any possibly other fixed type – that can't work!</p> <p>The solution that you want is this: <em><code>Container</code> shouldn't be existential, either</em>! The opti-function should work for any type which is in <code>Ord</code>, not just for one particular type. Well, as a GADT this looks about the same as the universally-quantified signature you originally had for <code>optimize</code>:</p> <pre><code>data Container a where (:/-&gt;) :: (forall v. Ord v =&gt; OptiF a v) -&gt; (a-&gt;Int) -&gt; Container a </code></pre> <p>With that now, optimize works</p> <pre><code>optimize :: Ord v =&gt; (a -&gt; v) -&gt; Container a -&gt; Int optimize val (opti :/-&gt; result) = result (opti val) </code></pre> <p>and can be used as you wanted</p> <pre><code>callOptimize :: Int callOptimize = optimize val cont where val = (*3) opti val' = if val' 1 &gt; val' 0 then 100 else -100 cont = opti :/-&gt; (*2) </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload