Haskell 如何使GHC识别此代码段中的SingI实例?
有一个关于 我有一个提升的数据类型Haskell 如何使GHC识别此代码段中的SingI实例?,haskell,ghc,singleton-type,Haskell,Ghc,Singleton Type,有一个关于 我有一个提升的数据类型a,其中我适当地实例化了数据族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
a
,其中我适当地实例化了数据族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
,让type家族完成这两项工作。除此之外,我也有很多类似的函数,我不希望每一个都需要这样做
我确实打开了ScopedTypeVariables
谢谢大家
编辑:啊,我刚刚意识到,
SingI
实例不是自动派生的;我突然想出了一个:
instance SingI NZ where
sing = SNZ
instance SingI n => SingI (NS n) where
sing = SNS sing
不幸的是,GHC仍然告诉我,当我在上面的lambda中使用sing
时,没有SingI
的实例:/
我觉得我应该可以在这里使用singI,让类型
家庭负责这两项工作
这是办不到的。我们在Singleton
中拥有许多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
类型同义词、Sing
、类型族和构造函数的失效符号,还可以为Eq
和Ord
键入电平类似物,以及。您可以点击模块上的:bro
,然后点击:i PNat
,以准确了解生成的内容
现在nPlus
和类型系列nPlus
可以按预期工作
关于SingI
,singia=>t
相当于singia->t
。它们甚至编译成完全相同的核心代码。它们之间唯一的区别是Sing
-s显式传递,而SingI
-s隐式传递sing
提供从SingI
到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
?最方便的方法是对Sing
-s执行计算,因为我们可以对它们进行模式匹配,并且仅当我们只需要插入或传递某个值,而不需要模式匹配或递归时才使用SingI
啊,谢谢:)这看起来确实是目前最好的方法,可以很好地利用单例的全部功能,而不需要大量的代码复制。。。。