[英]How do I make the GHC recognize a SingI instance in this snippet?
had a question about singletons有一个关于单身人士的问题
I have a promoted data type a
where I instanced data family Sing (a :: Foo)
appropriately.我有一个提升的数据类型
a
,我a
其中适当地实例化了data family Sing (a :: Foo)
。
I also have a type family Bar (a :: Foo) (b :: Foo) :: Foo
我也有一个类型家族
Bar (a :: Foo) (b :: Foo) :: Foo
In the middle of a busy function, I have:在繁忙的功能中,我有:
(\(x :: Sing n) (y :: Sing m) -> doThingsWith (sing :: Sing (Bar n m)))
But I'm not sure where I should put my SingI
constraint.但我不确定应该把
SingI
约束放在SingI
。
For more details, my type is有关更多详细信息,我的类型是
data PNat = NZ | NS PNat
data instance Sing (n :: PNat) where
SNZ :: Sing 'NZ
SNS :: Sing (m :: PNat) -> Sing ('NS m)
and my type family is我的字体家族是
type family NPlus (n :: PNat) (m :: PNat) :: PNat where
NPlus NZ y = y
NPlus (NS x) y = NS (NPlus x y)
Now, I'm actually able to manually write out explicit singleton shuffling:现在,我实际上能够手动写出显式单例改组:
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)
And this compiles fine...I can do这编译得很好......我可以做到
\x y -> nPlus x y
but I feel like I should be able to just use singI
here and let the type family do both of the work.但我觉得我应该能够在这里使用
singI
并让singI
系列完成这两项工作。 Besides, I have a lot of functions like this, too, and would prefer to not have to do it for each one.此外,我也有很多这样的功能,我宁愿不必为每个功能都做。
I do have ScopedTypeVariables turned on.我确实打开了 ScopedTypeVariables。
thank you all谢谢你们
Edit: Ah, I just realized that SingI
instances aren't automatically derived;编辑:啊,我刚刚意识到
SingI
实例不是自动派生的; I whipped one up:我挑了一个:
instance SingI NZ where
sing = SNZ
instance SingI n => SingI (NS n) where
sing = SNS sing
Unfortunately, GHC is still telling me that there is no instance of SingI
when I use sing
in the lambda above :/不幸的是,当我在上面的 lambda 中使用
sing
时,GHC 仍然告诉我没有SingI
实例:/
I feel like I should be able to just use singI here and let the type family do both of the work.
我觉得我应该能够在这里使用 singI 并让字体系列完成这两项工作。
This can't be done.这是做不到的。 The reason why we have the many TH facilities in
singletons
is that data and function definitions must be duplicated in the current state of affairs.我们在
singletons
有许多 TH 设施的原因是数据和函数定义必须在当前状态下重复。
The idiomatic usage would be defining everything on the term level once, and deriving the rest with 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) |])
This creates the Sing
definition,the type family for nPlus
, SingI
instances, SingKind
instances, the kind-restricted SPNat
type synonym for Sing
, defunctionalization symbols for type families and constructors, and also type-level analogues for Eq
and Ord
, and also decidable equality .这将创建
Sing
定义、 nPlus
的类型族、 SingI
实例、 SingKind
实例、 Sing
的种类限制SPNat
类型同义词、类型族和构造函数的去功能化符号,以及Eq
和Ord
类型级类似物,以及可判定的平等。 You can hit :bro
on the module and :i PNat
to find out exactly what got generated.您可以点击模块上的
:bro
和:i PNat
以准确找出生成的内容。
Now nPlus
and the type family NPlus
work as intended.现在
nPlus
和类型系列NPlus
按预期工作。
To provide a bit of explanation regarding SingI
: SingI a => t
is equivalent to Sing a -> t
.提供一些关于
SingI
的解释: SingI a => t
等价于Sing a -> t
。 They even compile to the exact same Core code.他们甚至编译成完全相同的核心代码。 The only difference between them is that
Sing
-s are passed explicitly and SingI
-s implicitly.它们之间的唯一区别是
Sing
-s 是显式传递的,而SingI
-s 是隐式传递的。 sing
provides conversion from SingI
to Sing
, and singInstance
converts backwards. sing
提供从SingI
到Sing
转换,而singInstance
向后转换。
In the light of this, something like鉴于此,类似
(SingI (NPlus n m)) => Sing n -> Sing m -> Sing (NPlus n m)
is pretty awkward, since it's equivalent to很尴尬,因为它相当于
Sing (NPlus n m) -> Sing n -> Sing m -> Sing (NPlus n m)
which can be implemented as a constant function that doesn't do any addition.它可以实现为一个不做任何加法的常量函数。
So when should we use SingI
or Sing
?那么我们什么时候应该使用
SingI
或Sing
呢? The most convenient way is to perform computation on Sing
-s, since we can pattern match on them, and use SingI
only when we just need to plug in or pass along a value somewhere, but don't need to pattern match or recurse.最方便的方法是在
Sing
-s 上执行计算,因为我们可以对它们进行模式匹配,并且仅当我们只需要在某处插入或传递值时才使用SingI
,但不需要模式匹配或递归。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.