类型级别约束编码
因此,我有一个仅在类型级别使用的数据构造函数,其中包含 Nat。通常,如果我在类型级别传递它,并且我想将 Nat
反映到术语级别,我需要一个 KnownNat
约束。我想要做的是将这个 KnownNat 约束编码到类型本身中,这样如果该类型出现在签名中的某处,就会在函数体中推断出 KnownNat 约束。这意味着我不再需要在使用站点编写 KnownNat
约束。我只需要确保在构造时满足 KnownNat
约束。
我想使用 GADT 来实现这一点,并得到了这么远:
data Foo = Foo Nat Nat
type family GetA (f :: Foo) :: Nat where
GetA ('Foo a _) = a
type family GetB (f :: Foo) :: Nat where
GetB ('Foo _ b) = b
data KnownFoo (f :: Foo) where
KnownFoo :: (KnownNat (GetA f), KnownNat (GetB f)) => KnownFoo f
foo :: forall (f :: Foo) (kf :: KnownFoo f). Proxy kf -> Integer
foo _ = natVal $ Proxy @(GetA f)
但这不起作用,因为类型检查器不理解 GetA f
是 KnownNat
即使 < code>KnownFoo 被传入。有没有办法让这样的事情工作?
我还尝试将 f :: Foo
完全移动到 KnownFoo
约束中,如下所示:
data Foo = Foo Nat Nat
type family GetA (f :: Foo) :: Nat where
GetA ('Foo a _) = a
type family GetB (f :: Foo) :: Nat where
GetB ('Foo _ b) = b
data KnownFoo where
KnownFoo :: forall f. (KnownNat (GetA f), KnownNat (GetB f)) => Proxy f -> KnownFoo
type family GetFoo (kf :: KnownFoo) :: Foo where
GetFoo ('KnownFoo (Proxy f)) = f
但是我无法编写 GetFoo
类型家庭,因为它抱怨 KnownNat
是不可提升的。
任何帮助表示赞赏!
So I have a data constructor that I only use at the type level which contains a Nat
. Normally if I pass this around at the type level and I want to reflect the Nat
to the term level I need a KnownNat
constraint. What I want to do is encode this KnownNat
constraint into the type itself so if this type occurs in a signature somewhere a KnownNat
constraint is inferred in the body of the function. This means I would no longer need to write the KnownNat
constraint at usage sites. I only need to make sure the KnownNat
constraint is met at construction.
I thought to use GADT for this and got this far:
data Foo = Foo Nat Nat
type family GetA (f :: Foo) :: Nat where
GetA ('Foo a _) = a
type family GetB (f :: Foo) :: Nat where
GetB ('Foo _ b) = b
data KnownFoo (f :: Foo) where
KnownFoo :: (KnownNat (GetA f), KnownNat (GetB f)) => KnownFoo f
foo :: forall (f :: Foo) (kf :: KnownFoo f). Proxy kf -> Integer
foo _ = natVal $ Proxy @(GetA f)
But this doesn't work as the type checker doesn't understand that GetA f
is a KnownNat
even though a KnownFoo
is passed in. Is there a way to make something like this work?
I also tried to move the f :: Foo
entirely into the KnownFoo
constraint like so:
data Foo = Foo Nat Nat
type family GetA (f :: Foo) :: Nat where
GetA ('Foo a _) = a
type family GetB (f :: Foo) :: Nat where
GetB ('Foo _ b) = b
data KnownFoo where
KnownFoo :: forall f. (KnownNat (GetA f), KnownNat (GetB f)) => Proxy f -> KnownFoo
type family GetFoo (kf :: KnownFoo) :: Foo where
GetFoo ('KnownFoo (Proxy f)) = f
But then I have no way to write the GetFoo
type family since it complains that KnownNat
is unpromotable.
Any help is appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不确定我是否完全理解您需要什么,但如果您想存储一个 KnownNat 约束,则必须有一些运行时表示。也许这样的东西可能对你有用:
请注意,
DataKinds
甚至不在这里:我们直接定义我们想要的新类型,而不是间接定义它的降低形式。我猜你可以为此创建一个类似的Known
类。不过,它似乎不是很有用。任何时候您可以编写
withKnownFoo x
,您已经在范围内拥有适当的KnownNat
实例来编写x
并满足其约束。I'm not sure I fully understand what you need, but if you want to store a
KnownNat
constraint, you'll have to have some runtime representation of that. Perhaps something like this may work for you:Note that
DataKinds
is not even on here: we are directly defining the new type we want rather than indirectly defining a lowered form of it. You can make a similarKnown
class for this, I guess.It doesn't seem super useful, though. Any time you could write
withKnownFoo x
, you already have the appropriateKnownNat
instances in scope to just writex
and have its constraints met anyway.