如何扩展 ghc-typelits-natnormalise 以检查通用和存在量化类型之间的关系?
How to extend ghc-typelits-natnormalise to check relationships between universally and existentially quantified types?
我试图通过使用 Proxy
s 代替 Integer
s 来完全安全且不偏不倚地使用 Finite
s:
-- SO test case, re: my use of ghc-typelits-natnormalise package.
--
-- David Banas <capn.freako@gmail.com>
-- February 9, 2018
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
module Bogus.NewFin where
import GHC.TypeLits
import Data.Proxy
import Data.Finite
import Data.Finite.Internal (Finite(..))
import Data.Reflection
-- A safer form of `finite`.
finite' :: (KnownNat n, KnownNat m, n `CmpNat` m ~ 'GT) => Proxy m -> Finite n
finite' p = Finite $ natVal p
-- A safer form of `getFinite`.
getFinite' :: KnownNat n => Finite n -> (forall m. (KnownNat m, n `CmpNat` m ~ 'GT) => Proxy m -> r) -> r
getFinite' x f = reifyNat (getFinite x) f
我遇到了这个编译器错误:
Davids-Air-2:test dbanas$ stack ghc -- -c so_natnorm.hs
so_natnorm.hs:28:41: error:
• Couldn't match type ‘CmpNat n n1’ with ‘'GT’
arising from a use of ‘f’
• In the second argument of ‘reifyNat’, namely ‘f’
In the expression: reifyNat (getFinite x) f
In an equation for ‘getFinite'’:
getFinite' x f = reifyNat (getFinite x) f
• Relevant bindings include
f :: forall (m :: Nat).
(KnownNat m, CmpNat n m ~ 'GT) =>
Proxy m -> r
(bound at so_natnorm.hs:28:14)
x :: Finite n (bound at so_natnorm.hs:28:12)
getFinite' :: Finite n
-> (forall (m :: Nat).
(KnownNat m, CmpNat n m ~ 'GT) =>
Proxy m -> r)
-> r
(bound at so_natnorm.hs:28:1)
我猜我的问题是试图通过 ghc-typelits-natnormalise 包提供的机制关联一个普遍存在的量化类型。对吗?
在我看来,这应该是允许的,因为调用者负责分配两者:
n
的值,以及
m
的最大值。
我对这个错误的推理在哪里?
reifyNat
将一个适用于 any natural 的函数作为参数。 forall m. (KnownNat m, n `CmpNat` m ~ 'GT) => Proxy m -> r
类型的函数对任何自然数都不起作用;它仅适用于比其他一些 n
少的天然植物。
由于您调用 getFinite
来生成实际值,因此您知道该值小于 n
。不幸的是,您无法向类型检查器证明这一点。幸运的是,您可以告诉类型检查器信任您:
import Type.Reflection ((:~:)(..))
import Unsafe.Coerce
...
getFinite'' :: KnownNat n => Finite n -> (forall m. (KnownNat m) => Proxy m -> n `CmpNat` m :~: 'GT -> r) -> r
getFinite'' x f = reifyNat (getFinite x) $ \p -> f p (unsafeCoerce Refl)
getFinite' :: forall n r . KnownNat n => Finite n -> (forall m. (KnownNat m, n `CmpNat` m ~ 'GT) => Proxy m -> r) -> r
getFinite' x f = getFinite'' x $ \p Refl -> f p
我试图通过使用 Proxy
s 代替 Integer
s 来完全安全且不偏不倚地使用 Finite
s:
-- SO test case, re: my use of ghc-typelits-natnormalise package.
--
-- David Banas <capn.freako@gmail.com>
-- February 9, 2018
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
module Bogus.NewFin where
import GHC.TypeLits
import Data.Proxy
import Data.Finite
import Data.Finite.Internal (Finite(..))
import Data.Reflection
-- A safer form of `finite`.
finite' :: (KnownNat n, KnownNat m, n `CmpNat` m ~ 'GT) => Proxy m -> Finite n
finite' p = Finite $ natVal p
-- A safer form of `getFinite`.
getFinite' :: KnownNat n => Finite n -> (forall m. (KnownNat m, n `CmpNat` m ~ 'GT) => Proxy m -> r) -> r
getFinite' x f = reifyNat (getFinite x) f
我遇到了这个编译器错误:
Davids-Air-2:test dbanas$ stack ghc -- -c so_natnorm.hs
so_natnorm.hs:28:41: error:
• Couldn't match type ‘CmpNat n n1’ with ‘'GT’
arising from a use of ‘f’
• In the second argument of ‘reifyNat’, namely ‘f’
In the expression: reifyNat (getFinite x) f
In an equation for ‘getFinite'’:
getFinite' x f = reifyNat (getFinite x) f
• Relevant bindings include
f :: forall (m :: Nat).
(KnownNat m, CmpNat n m ~ 'GT) =>
Proxy m -> r
(bound at so_natnorm.hs:28:14)
x :: Finite n (bound at so_natnorm.hs:28:12)
getFinite' :: Finite n
-> (forall (m :: Nat).
(KnownNat m, CmpNat n m ~ 'GT) =>
Proxy m -> r)
-> r
(bound at so_natnorm.hs:28:1)
我猜我的问题是试图通过 ghc-typelits-natnormalise 包提供的机制关联一个普遍存在的量化类型。对吗?
在我看来,这应该是允许的,因为调用者负责分配两者:
n
的值,以及m
的最大值。
我对这个错误的推理在哪里?
reifyNat
将一个适用于 any natural 的函数作为参数。 forall m. (KnownNat m, n `CmpNat` m ~ 'GT) => Proxy m -> r
类型的函数对任何自然数都不起作用;它仅适用于比其他一些 n
少的天然植物。
由于您调用 getFinite
来生成实际值,因此您知道该值小于 n
。不幸的是,您无法向类型检查器证明这一点。幸运的是,您可以告诉类型检查器信任您:
import Type.Reflection ((:~:)(..))
import Unsafe.Coerce
...
getFinite'' :: KnownNat n => Finite n -> (forall m. (KnownNat m) => Proxy m -> n `CmpNat` m :~: 'GT -> r) -> r
getFinite'' x f = reifyNat (getFinite x) $ \p -> f p (unsafeCoerce Refl)
getFinite' :: forall n r . KnownNat n => Finite n -> (forall m. (KnownNat m, n `CmpNat` m ~ 'GT) => Proxy m -> r) -> r
getFinite' x f = getFinite'' x $ \p Refl -> f p