有关于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
的实例:/
答案 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
定义,nPlus
,SingI
个实例,SingKind
个实例的类型系列,SPNat
类型的同义词{ {1}},类型系列和构造函数的defunctionalization符号,以及Sing
和Eq
以及decidable equality的类型级别类似物。您可以点击模块上的Ord
和:bro
以确切了解生成的内容。
现在:i PNat
和类型系列nPlus
按预期工作。
就NPlus
提供一些解释:SingI
相当于SingI a => t
。他们甚至编译为完全相同的核心代码。它们之间的唯一区别是Sing a -> t
- s显式传递,Sing
- s隐式传递。 SingI
提供从sing
到SingI
的转换,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
,但不要需要模式匹配或递归。