Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to write fmap for this data type involving a type family?

Given the following type family (supposed to reflect the isomorphism A×1 ≅ A)

type family P (x :: *) (a :: *) :: * where
  P x () = x
  P x a  = (x, a)

and data type defined in terms thereof

data T a = T Integer (P (T a) a)

is it possible by some type hackery to write a Functor instance for the latter?

instance Functor T where
  fmap f = undefined  -- ??

Intuitively, it's obvious what to do depending on the type of f, but I don't know how to express it in Haskell.

like image 574
Sebastien Avatar asked Jan 14 '15 06:01

Sebastien


1 Answers

I tend to reason about these kind higher kind programs using Agda.

The problem here is that you want to pattern match on * (Set in Agda), violate parametericity, as mentioned in the comment. That is not good, so you cannot just do it. You have to provide witness. I.e. following is not possible

P : Set → Set → Set
P Unit b = b
P a b = a × b

You can overcome the limitiation by using aux type:

P : Aux → Set → Set
P auxunit b     = b
P (auxpair a) b = a × b

Or in Haskell:

data Aux x a = AuxUnit x | AuxPair x a

type family P (x :: Aux * *) :: * where
  P (AuxUnit x) = x
  P (AuxPair x a) = (x, a)

But doing so you'll have problems expressing T, as you need to pattern match on its parameter again, to select right Aux constructor.


"Simple" solution, is to express T a ~ Integer when a ~ (), and T a ~ (Integer, a) directly:

module fmap where

record Unit : Set where
  constructor tt

data ⊥ : Set where

data Nat : Set where
  zero : Nat
  suc : Nat → Nat

data _≡_ {ℓ} {a : Set ℓ} : a → a → Set ℓ where
  refl : {x : a} → x ≡ x

¬_ : ∀ {ℓ} → Set ℓ → Set ℓ
¬ x = x → ⊥

-- GADTs
data T : Set → Set1 where
  tunit : Nat → T Unit
  tpair : (a : Set) → ¬ (a ≡ Unit) → a → T a

test : T Unit → Nat
test (tunit x) = x
test (tpair .Unit contra _) with contra refl
test (tpair .Unit contra x) | ()

You can try to encode this in Haskell to.

You can express it using e.g. 'idiomatic' Haskell type inequality

I'll leave the Haskell version as an exercise :)


Hmm or did you meant by data T a = T Integer (P (T a) a):

T () ~ Integer × (P (T ()) ())
     ~ Integer × (T ())
     ~ Integer × Integer × ... -- infinite list of integers?

-- a /= ()
T a ~ Integer × (P (T a) a)
    ~ Integer × (T a × a) ~ Integer × T a × a
    ~ Integer × Integer × ... × a × a

Those are easier to encode directly as well.

like image 188
phadej Avatar answered Sep 28 '22 09:09

phadej