Skip to content

Instantly share code, notes, and snippets.

@cblp
Last active August 21, 2017 12:00
Show Gist options
  • Save cblp/b9e0d3aac0ab8e496a9930d74e3b8f57 to your computer and use it in GitHub Desktop.
Save cblp/b9e0d3aac0ab8e496a9930d74e3b8f57 to your computer and use it in GitHub Desktop.
Example of usage of an existential type as a sum type.
#!/usr/bin/env stack
-- stack --resolver=lts-9.0 script --package=singletons
{-# OPTIONS_GHC -Wall -Werror #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
import Data.Kind (Type)
import Data.Singletons (Sing, SingI, sing)
import Data.Singletons.TH (genSingletons)
data LetterName = Alpha | Beta
genSingletons [''LetterName]
data family LetterSpecific :: LetterName -> Type
data instance LetterSpecific 'Alpha = LetterAlpha Int
data instance LetterSpecific 'Beta = LetterBeta Char
data Letter
= forall (letter :: LetterName)
. SingI letter => Letter (LetterSpecific letter)
matchLetter
:: (forall letter . (Sing letter, LetterSpecific letter) -> a)
-> Letter
-> a
matchLetter go (Letter (spec :: LetterSpecific letter)) =
go (sing :: Sing letter, spec)
extract :: Letter -> String
extract = matchLetter $ \case
(SAlpha, LetterAlpha int ) -> "alpha " ++ show int
(SBeta , LetterBeta char) -> "beta " ++ [char]
main :: IO ()
main = print $ map extract [Letter $ LetterAlpha 1, Letter $ LetterBeta 'B']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment