1

Why it is not possible to pattern match existential types in let/where, while it is doable in all other places?

TL;DR I have a funny error during let pattern matching of existential types:

error:
• My brain just exploded
  I can't handle pattern bindings for existential or GADT data constructors.
  Instead, use a case-expression, or do-notation, to unpack the constructor.
• In the pattern: MC q
  In a pattern binding: MC q = x
  In the expression: let MC q = x in bar q

Details: let us start with some simple code:

{-# LANGUAGE ExistentialQuantification #-}

class MyClass a where
  foo :: a -> Int

instance MyClass Int where
  foo = id

instance MyClass Char where
  foo = const 4

data MC = forall a. MyClass a => MC a

bar :: MyClass a => a -> Int
bar = (+1) . foo

This function runs great:

baz :: MC -> Int
baz (MC q) = bar q

and this:

qux :: MC -> Int
qux x = case x of
          MC q -> bar q

even this:

import Control.Monad.Identity

osе :: MC -> Int
ose x = runIdentity $ do MC q <- pure x
                         pure $ bar q

but these two fail:

rol :: MC -> Int
rol x = let MC q = x
        in bar q

zed :: MC -> Int
zed x = bar q
  where MC q = x
  • Welcome to StackOverflow! Your question was well posed, but make sure you search for existing questions before posting a new one. – jkeuhlen May 11 '17 at 15:49
  • `let` and `where` involve lazy (AKA irrefutable) patterns, which do not force the argument (`x`, above). It would be very weird if laziness was lost only because there's a typeclass dictionary to unpack, especially because said dictionary does not explicitly occur in the code. – chi May 11 '17 at 17:46

0 Answers0