I am reading the Rank-N-Types section of 24 days of GHC Extensions and came across the following GADT:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
import Data.Char
data Some :: * -> * where
SomeInt :: Int -> Some Int
SomeChar :: Char -> Some Char
Anything :: a -> Some a
unSome :: Some a -> a
unSome (SomeInt x) = x + 3
unSome (SomeChar c) = toLower c
unSome (Anything x) = x
unSome (someInt 2) -- 5
Although unSome
is polymorphic in its type variables one can give the compiler proof that in the SomeInt
case for instance, it is safe to add three to the given value. The author calls this type refinement.
Now I was curious whether I can do the same with a Scrott encoded type. Fortunately, there is an example of such encoding. We merely need the Rank-N-Types and Type-Families extensions turned on:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}
newtype SomeC a =
SomeC {
runSomeC ::
forall r.
((a ~ Int) => Int -> r) ->
((a ~ Char) => Char -> r) ->
(a -> r) ->
r
}
However, unSome
isn't provided in the article. I am not well-versed in Haskell and don't have a clue how to implement this function with Scott encoding. Especially the type equality constraints (e.g. (a ~ Int) =>
) confuse me.
Any help or information on other online sources are appreciated.
You just use the provided function to replace your pattern match, as in:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}
import Data.Char
newtype SomeC a =
SomeC {
runSomeC ::
forall r.
((a ~ Int) => Int -> r) ->
((a ~ Char) => Char -> r) ->
(a -> r) ->
r
}
unSome :: SomeC a -> a
unSome (SomeC f) = f (\x -> x+3) (\c -> toLower c) (\x -> x)
In ghci:
> unSome (SomeC (\someInt someChar anything -> someInt 2))
5