0

So I would like to implement a function that applies a value to the nth argument of a function, lets call it inject:

inject :: (???) => a -> f -> ???

So I declared a class representing all Applicable triples (n, a, f). Note that n must be bigger than 0 and a depends on f and n

class (1 <= n) => Applicable n a f | f n -> a where
  type ApplyAt n a f :: Type
  inject :: a -> f -> ApplyAt n a f

We can then do some induction on n:

instance Applicable 1 a (a -> b) where
  type ApplyAt 1 a (a -> b) = b
  inject a f = f a

instance (Applicable (n - 1) a c) => Applicable n (a :: Type) (b -> c) where
  type ApplyAt n a (b -> c) = b -> ApplyAt (n - 1) a c
  inject a f = \x -> inject @(n - 1) a (f x)

Applicable n a (b -> c) implies Applicable (n - 1) a c which implies n - 1 >= 1 or n >= 2 so these instance declarations are not overlapping. But GHC proceeds to complain:

Conflicting family instance declarations:
  ApplyAt 1 a (a -> b) = b
  ApplyAt n a (b -> c) = b -> ApplyAt (n - 1) a c

What should I do to convince GHC that these type familiy declarations are not overlapping?

Poscat
  • 565
  • 3
  • 15

1 Answers1

0

The solution is to use inductively defined natural numbers/positive integers which avoids overlapping instances.

data NPlus = One | Suc NPlus

class Applicable (n :: NPlus) a f | f n -> a where
  type ApplyAt n a f :: Type
  inject :: a -> f -> ApplyAt n a f

instance Applicable One a (a -> b) where
  type ApplyAt One a (a -> b) = b
  inject a f = f a

instance (Applicable n a c) => Applicable (Suc n) (a :: Type) (b -> c) where
  type ApplyAt (Suc n) a (b -> c) = b -> ApplyAt n a c
  inject a f = \x -> inject @n a (f x)

-- >>> inject @(Suc One) 1 (\y x -> (y + 3) * x) 2
-- 5
--
Poscat
  • 565
  • 3
  • 15