<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>Hi Li-yao,</p>
    <p>Thanks for your answer. Sadly I haven't managed to make it work
      this way neither.</p>
    <p>In addition I need a "KnownNat (n-1)" while I only have "KnownNat
      n" (and the knowledge that n > 0). For the record, it works
      with an unsafeCoerce:</p>
    <p><tt>data V2 (vs :: [k]) where</tt><tt><br>
      </tt><tt>    V2 :: forall vs (n :: Nat). KnownNat n => Proxy n
        -> Index n vs -> V2 vs</tt><tt><br>
      </tt><tt><br>
      </tt><tt>splitV2 :: forall v vs. V2 (v:vs) -> Either (V2 vs) v</tt><tt><br>
      </tt><tt>{-# INLINE splitV2 #-}</tt><tt><br>
      </tt><tt>splitV2 = \case</tt><tt><br>
      </tt><tt>    V2 (n1 :: Proxy n) v -> case sameNat n1 (Proxy @0)
        of</tt><tt><br>
      </tt><tt>       Just Refl -> Right v</tt><tt><br>
      </tt><tt>       Nothing   -> case someNatVal (natVal n1 - 1) of</tt><tt><br>
      </tt><tt>         SomeNat (n2 :: Proxy n') -> case unsafeCoerce
        Refl :: Index n (v:vs) :~: Index n' vs of</tt><tt><br>
      </tt><tt>            Refl -> Left (V2 n2 v)</tt><tt><br>
      </tt><tt><br>
      </tt><tt>instance Show (V2 '[]) where</tt><tt><br>
      </tt><tt>   {-# INLINABLE show #-}</tt><tt><br>
      </tt><tt>   show = undefined</tt><tt><br>
      </tt><tt><br>
      </tt><tt>instance (Show x, Show (V2 xs)) => Show (V2 (x ': xs))
        where</tt><tt><br>
      </tt><tt>   {-# INLINABLE show #-}</tt><tt><br>
      </tt><tt>   show v = case splitV2 v of</tt><tt><br>
      </tt><tt>      Right x -> show x</tt><tt><br>
      </tt><tt>      Left xs -> show xs</tt></p>
    <p><tt>test :: V2 '[Int,Word,String] -> String</tt><tt><br>
      </tt><tt>test v = show v</tt><br>
    </p>
    <p>However the generated Core isn't as pretty as with the previous
      representation <span class="kt">(which uses unsafeCoerce for the
        value, not for the index)</span>:</p>
    <pre><span class="kr">data</span> <span class="kt">Variant</span> <span class="p">(</span><span class="n">types</span> <span class="ow">::</span> <span class="p">[</span><span class="o">*</span><span class="p">])</span> <span class="ow">=</span> <span class="kt">Variant</span> <span class="cm">{-# UNPACK #-}</span> <span class="o">!</span><span class="kt">Word</span> <span class="kt">Any

</span></pre>
    <span class="kt">I'll stick to this one for now.<br>
    </span><br>
    Sylvain<br>
    <span class="kt"></span>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 21/08/2019 16:46, Li-yao Xia wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:159641df-6a6a-45b7-3618-b80b3489d5f0@gmail.com">Hi
      Sylvain,
      <br>
      <br>
      The problem is that in the case where `n1` is not equal to `0`,
      this unequality is not made available as a constraint solver
      (whereas in the case where they are equal, the `Refl` constructor
      makes the corresponding equality constraint available).
      <br>
      <br>
      In fact, there is no built-in "unequality constraint" that acts as
      a counterpart to `~` (it does not seem quite straightforward how
      that would even work), but there is one way to encode it as a
      boolean type family `((n == 0) ~ 'False)`. That requires changing
      type families to pattern-match on `n == 0` instead of `n`
      directly, and possibly additional gymnastics to reflect the
      comparison at term-level:
      <br>
      <br>
      <br>
      type Index n l = IndexIf (n == 0) n l
      <br>
      <br>
      type family IndexIf (b :: Bool) (n :: Nat) (l :: [k]) :: k where
      <br>
        IndexIf 'False n (x ': _ ) = x
      <br>
        IndexIf 'True  n (_ ': xs) = Index (n - 1) xs
      <br>
      <br>
      <br>
      Cheers,
      <br>
      Li-yao
      <br>
      <br>
      On 8/21/19 9:09 AM, Sylvain Henry wrote:
      <br>
      <blockquote type="cite">Hi,
        <br>
        <br>
        Suppose I have the following type family:
        <br>
        <br>
        type family Index (n :: Nat) (l :: [k]) = (r :: k) where
        <br>
            Index 0 (x ': _ ) = x
        <br>
            Index n (_ ': xs) = Index (n-1) xs
        <br>
        <br>
        I'm using it to define a Variant type:
        <br>
        <br>
        data V2 (vs :: [k]) where
        <br>
            V2 :: forall vs (n :: Nat). KnownNat n => Proxy n ->
        Index n vs -> V2 vs
        <br>
        <br>
        Now I want to match on the Variant retrieving either the head or
        the tail (another Variant):
        <br>
        <br>
        splitV2 :: forall v vs. V2 (v:vs) -> Either v (V2 vs)
        <br>
        splitV2 = \case
        <br>
            V2 (n1 :: Proxy n) v -> case sameNat n1 (Proxy @0) of
        <br>
                  Just Refl -> Left v
        <br>
                  Nothing   -> Right (V2 (Proxy @(n-1)) v)
        <br>
        <br>
        It fails to typecheck with:
        <br>
        <br>
        Couldn't match type ‘Index n (v : vs)’ with ‘Index (n - 1) vs’
        <br>
        Expected type: Index (n - 1) vs
        <br>
        Actual type: Index n vs1
        <br>
        NB: ‘Index’ is a non-injective type family
        <br>
        <br>
        <br>
        Is there a way to make this work?
        <br>
        <br>
        <br>
        This is highly speculative as I'm not very familiar with
        type-checking: would it be sound to make the inductive Index
        family "weakly" injective? I.e. somehow produce a typing rule
        for the type family:
        <br>
        <br>
           forall n n' x xs xs'.
        <br>
             Solving: Index n (x ': xs) ~ Index (n'-1) xs'
        <br>
             Is equivalent to solving: if n /= 0 then (n ~ n', xs ~ xs')
        else (x ~ Index (n'-1) xs')
        <br>
        <br>
        Here we could know that "n /= 0" thanks to the match on "sameNat
        n1 (Proxy @0)".
        <br>
        <br>
        ("weakly" because we have some form of injectivity on the shape
        of the list but not on its contents)
        <br>
        <br>
        Any pointer on this kind of stuff in research papers, Coq, Agda,
        etc. ?
        <br>
        <br>
        Thanks,
        <br>
        Sylvain
        <br>
        <br>
        _______________________________________________
        <br>
        Haskell-Cafe mailing list
        <br>
        To (un)subscribe, modify options or view archives go to:
        <br>
        <a class="moz-txt-link-freetext" href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a>
        <br>
        Only members subscribed via the mailman list are allowed to
        post.
        <br>
      </blockquote>
    </blockquote>
  </body>
</html>