如何从具有类型相等约束的 Scott 编码的 GADT 中获取值?

How to get the value from a Scott encoded GADT with type equality constraints?

我正在阅读 the Rank-N-Types section of 24 days of GHC Extensions 并遇到了以下 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

虽然 unSome 在其类型变量中是多态的,但我们可以向编译器证明,例如在 SomeInt 的情况下,给定值加三是安全的。作者将这种类型称为细化。

现在我很好奇我是否可以对 Scrott 编码类型做同样的事情。幸运的是,有一个这种编码的例子。我们只需要打开 Rank-N-Types 和 Type-Families 扩展:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}

newtype SomeC a =
    SomeC {
      runSomeC ::
          forall r.
          ((a ~ Int) => Int -> r) ->
          ((a ~ Char) => Char -> r) ->
          (a -> r) ->
          r
    }

但是,文章中没有提供 unSome。我不精通 Haskell 并且不知道如何使用 Scott 编码实现此功能。特别是类型等式约束(例如 (a ~ Int) =>)让我很困惑。

感谢任何有关其他在线资源的帮助或信息。

您只需使用提供的函数来替换您的模式匹配,如:

{-# 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)

在 ghci 中:

> unSome (SomeC (\someInt someChar anything -> someInt 2))
5