如何让GHC识别此片段中的SingI实例?

时间:2015-09-02 22:53:49

标签: haskell ghc singleton-type

有关于singletons

的问题

我有一个提升的数据类型a,其中我恰当地data family Sing (a :: Foo)实例化。

我还有一个类型系列Bar (a :: Foo) (b :: Foo) :: Foo

在繁忙的功能中,我有:

(\(x :: Sing n) (y :: Sing m) -> doThingsWith (sing :: Sing (Bar n m)))

但我不知道应该在哪里设置SingI约束。

有关详细信息,我的类型是

data PNat = NZ | NS PNat

data instance Sing (n :: PNat) where
  SNZ :: Sing 'NZ
  SNS :: Sing (m :: PNat) -> Sing ('NS m)

我的类型系列是

type family NPlus (n :: PNat) (m :: PNat) :: PNat where
  NPlus NZ y = y
  NPlus (NS x) y = NS (NPlus x y)

现在,我实际上能够手动写出显式单例改组:

nPlus :: forall n m nm. (NPlus n m ~ nm) => Sing n -> Sing m -> Sing nm
nPlus SNZ y = y
nPlus (SNS x) y = SNS (nPlus x y)

这编译得很好......我可以做到

\x y -> nPlus x y

但我觉得我应该能够在这里使用singI并让类型系列完成这两项工作。此外,我也有很多这样的功能,并且不希望每个人都这样做。

我确实打开了ScopedTypeVariables。

谢谢大家

编辑:啊,我刚刚意识到SingI个实例没有自动派生;我鞭打了一个:

instance SingI NZ where
  sing = SNZ

instance SingI n => SingI (NS n) where
  sing = SNS sing

不幸的是,当我在上面的lambda中使用SingI时,GHC仍然告诉我没有sing的实例:/

1 个答案:

答案 0 :(得分:2)

  

我觉得我应该能够在这里使用singI并让它输入   家人做了两件事。

这不可能。我们在singletons中拥有许多TH工具的原因是数据和函数定义必须在当前事态中重复。

习惯用法是定义术语等级上的所有内容,然后用TH得出其余内容。

-- LANGUAGE KitchenSink
import Data.Singletons.TH
import Data.Singletons.Prelude

$(singletons [d|
  data PNat = NZ | NS PNat deriving (Eq, Show, Ord)

  nPlus :: PNat -> PNat -> PNat
  nPlus NZ y = y
  nPlus (NS x) y = NS (nPlus x y)  |])

这将创建Sing定义,nPlusSingI个实例,SingKind个实例的类型系列,SPNat类型的同义词{ {1}},类型系列和构造函数的defunctionalization符号,以及SingEq以及decidable equality的类型级别类似物。您可以点击模块上的Ord:bro以确切了解生成的内容。

现在:i PNat和类型系列nPlus按预期工作。

NPlus提供一些解释:SingI相当于SingI a => t。他们甚至编译为完全相同的核心代码。它们之间的唯一区别是Sing a -> t - s显式传递,Sing - s隐式传递。 SingI提供从singSingI的转换,singInstance向后转换。

鉴于此,

之类的东西
Sing

非常尴尬,因为它相当于

(SingI (NPlus n m)) => Sing n -> Sing m -> Sing (NPlus n m)

可以实现为不进行任何添加的常量函数。

那么我们什么时候应该使用Sing (NPlus n m) -> Sing n -> Sing m -> Sing (NPlus n m) SingI?最方便的方法是在Sing - s上执行计算,因为我们可以对它们进行模式匹配,并且仅在我们需要插入或传递某个值时才使用Sing,但不要需要模式匹配或递归。