How to remove a pattern matching expression (or how to use existential types as a restricted class and a specific type.)

consider

data Foo1 = Foo1 { f1 :: Int }
data Foo2 = Foo2 { f2 :: Int }
data Foo3 = Foo3 { f3 :: Int }

data Thing = 
    Thing1 Foo1
  | Thing2 Foo2
  | Thnig3 Foo3

bar :: Thing -> Int
bar (Thing1 foo1) = f1 foo1
bar (Thing2 foo2) = f2 foo2
..

this is clearly insane.

how can i fix this?

I tried

class Foo g where
  f :: g -> Int

instance Foo (Foo1) where
  f = f1
...

but this does not help, as I still cannot write barwithout matching the pattern.

I want to

bar :: Thing -> Int
bar (_ foo) = f foo

but this is unreal.

(I can parameterize Thing as foo, and then it will work fine, but I cannot do it in my actual code, that is, I need Thing to be completely general. why should I make a pattern matching k times for FooK, if I said that some class is defined that they all work.)

+4
source share
2 answers

, , , , .

{-# LANGUAGE GADTs #-}

data Foo1 = Foo1 { f1 :: Int }
data Foo2 = Foo2 { f2 :: Int }
data Foo3 = Foo3 { f3 :: Int }

class Foo g where
  f :: g -> Int

-- A singleton type which introduces a unique constructor
-- for each type you want to store in the existential.
data SFoo t where
    SFoo1 :: SFoo Foo1
    SFoo2 :: SFoo Foo2
    SFoo3 :: SFoo Foo3

-- The type parameter of the singleton matches with the existential.
-- This allows us to use pattern matching to find out the real type
-- of "t" later on.
data Thing where
    Thing :: Foo t => SFoo t -> t -> Thing

-- Now you can use the existential through the type-class
bar :: Thing -> Int
bar (Thing _ foo) = f foo

-- And you can also pattern match on a specific constructor
-- when needed. Pattern matching on the singleton "SFoo1"
-- convinces the type-checker that the existential field
-- must have a type of "Foo1" which lets you use it normally.
bar2 :: Thing -> Maybe Int
bar2 (Thing SFoo1 (Foo1 i)) = Just i
bar2 _ = Nothing
+4

! , Haskell98, GHC.

Thing, , Foo.

{-# LANGUAGE ExistentialQuantification #-}

class Foo g where
  f :: g -> Int

data Foo1 = Foo1 { f1 :: Int }
instance Foo (Foo1) where f = f1

data Thing = forall a . Foo a => Thing a

bar :: Thing -> Int
bar (Thing t) = f t

. " ": https://en.wikibooks.org/wiki/Haskell/Existentially_quantified_types

1:

FooN, , , . , , FooThing Thing, , , FooThing

{-# LANGUAGE ExistentialQuantification #-}

class Foo g where
  f :: g -> Int

data Foo1 = Foo1 { f1 :: Int }
instance Foo (Foo1) where f = f1

data Thing = Thing1 Foo1

data FooThing = forall a . Foo a => FooThing a

fooThing :: Thing -> FooThing
fooThing (Thing1 t) = FooThing t

bar :: Thing -> Int
bar = g . fooThing
  where g (FooThing t) = f t

Foo Thing

instance Foo (Thing) where
 f = g . fooThing
   where g (FooThing t) = f t

2:

shang, GADT, , , Thing Foo1 `` `Foo``,

{-# LANGUAGE GADTs #-}

class Foo g where
  f :: g -> Int

data Foo1 = Foo1 { f1 :: Int }
instance Foo (Foo1) where f = f1

data Thing where
     Thing :: Foo t => t -> Thing

bar :: Thing -> Int
bar (Thing foo) = f foo
+1

All Articles