Skip to content

Illegal type synonym family application when promoting a function on singleton-indexed types #627

@fpringle

Description

@fpringle

I'm trying to define a fixed-length vector type, indexed by Peano numbers, then promote the vector, and define an append operation on that vector, both at the type and the value level. I need the defunctionalisation symbols because I'm going to use this family later in a more complicated function, which I'll also want to promote.

{-# LANGUAGE TemplateHaskell #-}

import Data.Singletons.TH
import Data.Singletons.TH.Options

$( withOptions defaultOptions {genSingKindInsts = False}
    $ singletons
      [d|
        data N = Z | S N

        (++) :: N -> N -> N
        Z ++ m = m
        S n ++ m = S (n ++ m)

        type Vec :: N -> Type -> Type
        data Vec n a where
          VNil :: Vec 'Z a
          (:.) :: a -> Vec n a -> Vec ('S n) a
        |]
 )

$( singletons
    [d|
      (+++) :: Vec n a -> Vec m a -> Vec (n ++ m) a
      VNil +++ ys = ys
      (x :. xs) +++ ys = x :. (xs +++ ys)
      |]
 )

GHC refuses to compile the second splice, with the following error:

src/Lambda/TypeLevel/Example.hs:24:2: error: [GHC-73138]
    • Illegal type synonym family application ‘n ++ m’ in instance:
        Apply
          @(Vec n a)
          @(Vec m a ~> Vec (n ++ m) a)
          ((+++@#@$) @n @a @m)
          a6989586621679086404
    • In the type instance declaration for ‘Apply’
   |
24 | $( singletons
   |  ^^^^^^^^^^^^...

The generated code (cleaned up) is:

(+++) :: Vec n a -> Vec m a -> Vec (n ++ m) a
(+++) VNil ys = ys
(+++) (x :. xs) ys = x :. (xs +++ ys)

type (+++@#@$) :: (~>) (Vec n a) ((~>) (Vec m a) (Vec (n ++ m) a))
data (+++@#@$) :: (~>) (Vec n a) ((~>) (Vec m a) (Vec (n ++ m) a)) where
  (:+++@#@$###) ::
    (SameKind (Apply (+++@#@$) arg) ((+++@#@$$) arg)) => (+++@#@$) a

type instance Apply (+++@#@$) v1 = (+++@#@$$) v1

instance SuppressUnusedWarnings (+++@#@$) where
  suppressUnusedWarnings = snd ((,) (:+++@#@$###) ())

type (+++@#@$$) ::
  Vec n a ->
  (~>) (Vec m a) (Vec (n ++ m) a)
data (+++@#@$$) (v1 :: Vec n a) :: (~>) (Vec m a) (Vec (n ++ m) a) where
  (:+++@#@$$###) ::
    (SameKind (Apply ((+++@#@$$) v1) arg) ((+++@#@$$$) v1 arg)) =>
    (+++@#@$$) v1 v2

type instance Apply ((+++@#@$$) v1) v2 = (+++) v1 v2

instance SuppressUnusedWarnings ((+++@#@$$) v1) where
  suppressUnusedWarnings = snd ((,) (:+++@#@$$###) ())

type (+++@#@$$$) :: Vec n a -> Vec m a -> Vec (n ++ m) a
type family (+++@#@$$$) (v1 :: Vec n a) (v2 :: Vec m a) :: Vec (n ++ m) a where
  (+++@#@$$$) v1 v2 = (+++) v1 v2

type (+++) :: Vec n a -> Vec m a -> Vec (n ++ m) a
type family (+++) (a_abqp :: Vec n a) (a_abqq :: Vec m a) :: Vec (n ++ m) a where
  (+++) 'VNil ys = ys
  (+++) ('(:.) x xs) ys = Apply (Apply (:.@#@$) x) (Apply (Apply (+++@#@$) xs) ys)

(%+++) ::
  ( forall
      (t1 :: Vec n a)
      (t2 :: Vec m a).
    Sing t1 ->
    Sing t2 ->
    Sing (Apply (Apply (+++@#@$) t1) t2 :: Vec (n m) a) ::
      Type
  )
(%+++) SVNil (sYs :: Sing ys) = sYs
(%+++) ((:%.) (sX :: Sing x) (sXs :: Sing xs)) (sYs :: Sing ys) =
  applySing
    (applySing (singFun2 @(:.@#@$) (:%.)) sX)
    (applySing (applySing (singFun2 @(+++@#@$) (%+++)) sXs) sYs)

instance SingI ((+++@#@$) :: (~>) (Vec n a) ((~>) (Vec m a) (Vec (n ++ m) a))) where
  sing = singFun2 @(+++@#@$) (%+++)

instance
  (SingI v) =>
  SingI ((+++@#@$$) (v :: Vec n a) :: (~>) (Vec m a) (Vec (n ++ m) a))
  where
  sing =
    singFun1
      @((+++@#@$$) (v :: Vec n a))
      ((%+++) (sing @v))

instance SingI1 ((+++@#@$$) :: Vec n a -> (~>) (Vec m a) (Vec (n ++ m) a)) where
  liftSing (s :: Sing (v :: Vec n a)) =
    singFun1
      @((+++@#@$$) (v :: Vec n a))
      ((%+++) s)

This feels like a fairly fundamental thing to want to do with singletons. Is there a standard way of getting round this problem?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions