Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a universal and existential quantifier for a constructor be commuted in pattern matching?

Tags:

haskell

Here is a snippet that I think makes (type) sense, but which ghc doesn't like. I was hoping that some tricky use of type annotations could make it work, but my experiments have failed. Any suggestions?

{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Ex where

data T a where
  T :: Functor f => (f a -> a) -> T a

foo :: (forall a . T a) -> Bool
foo (T f) = bar f

bar :: Functor f => (forall a . f a -> a) -> Bool
bar _f = True

It could very well be impossible since it amounts to commuting a universal and existential quantifier, but I was hoping.

like image 695
augustss Avatar asked Aug 04 '20 22:08

augustss


People also ask

Where are universal and existential quantifiers used?

The universal quantifier, meaning "for all", "for every", "for each", etc. The existential quantifier, meaning "for some", "there exists", "there is one", etc. A statement of the form: x, if P(x) then Q(x). A statement of the form: x such that, if P(x) then Q(x).

Does the order of existential and universal quantifiers matter?

If you have two existential quantifiers or two universal quantifiers, does the order make a difference? No, it does not.

What conditions use universal quantifier?

The Universal Quantifier. A sentence ∀xP(x) is true if and only if P(x) is true no matter what value (from the universe of discourse) is substituted for x. ∙ ∀x(x2≥0), i.e., "the square of any number is not negative.


1 Answers

I tried that example in Agda, to see if it makes sense

module Comm where

open import Data.Bool using (Bool; true)

record T (A : Set) : Set₁ where
  constructor MkT
  field
    F : Set → Set
    f : F A → A

bar : {F : Set → Set} → (∀ A → F A → A) → Bool
bar _ = true

foo : (∀ A → T A) → Bool
foo k = bar {F = k Bool .T.F} λ A → {!k A .T.f!}
-- Goal: k Bool .T.F A → A
-- Have: T.F. (k A) A → A

In foo, we need to instantiate forall a. T a with some type. As the type is parametric, any should do, and F would be the same. But neither Agda nor Haskell have that parametricity built in.

So I think that with right use of unsafeCoerce, things will work.

{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}

{-# LANGUAGE TypeApplications #-}
module Ex where

import Unsafe.Coerce (unsafeCoerce)
import Data.List.NonEmpty (NonEmpty (..))
import GHC.Exts (Any)

data T a where
  T :: Functor f => (f a -> a) -> T a

bar :: Functor f => (forall a . f a -> a) -> Bool
bar _f = _f `seq` True

foo :: (forall a . T a) -> Bool
foo t = foo' t t

foo' :: (forall a. T a) -> T Any -> Bool
foo' t (T f) = aux f where
    aux :: forall f. Functor f => (f Any -> Any) -> Bool
    aux f' = bar f''
      where
        f'' :: forall a. f a -> a
        f'' = unsafeCoerce f'

--- test

ex :: forall a. T a
ex = T (\(x :| _) -> x)

ex2 :: Bool
ex2 = foo ex
like image 158
phadej Avatar answered Oct 12 '22 05:10

phadej