将 `<=?` 替换为 `CmpNat`
Replacing `<=?` with `CmpNat`
我有以下类型:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.Kind
import GHC.TypeLits
import Data.Type.Bool
type family Valid (n :: Nat) :: Constraint where
Valid (n :: Nat) = ( KnownNat n
, If (2 <=? n && n <=? 16)
(() :: Constraint)
(TypeError ('Text "No Good"))
)
这按预期工作。但是 GHC 有一个 note,<=?
可能会被 CmpNat
取代。到目前为止,我尝试用 CmpNat
替换 <=?
的使用失败了。例如这个版本:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.Kind
import GHC.TypeLits
import Data.Type.Bool
type family Valid (n :: Nat) :: Constraint where
Valid (n :: Nat) = ( KnownNat n
, If ((CmpNat 2 n ~ 'EQ || CmpNat 2 n ~ 'LT) && (CmpNat n 16 ~ 'EQ || CmpNat n 16 ~ 'LT))
(() :: Constraint)
(TypeError ('Text "No Good"))
)
不仅更冗长,GHC 理所当然地不喜欢它,因为类型级布尔值 and/or 的组成部分本身不再是布尔值:
• Expected kind ‘Bool’,
but ‘CmpNat 2 n ~ 'EQ’ has kind ‘Constraint’
• In the first argument of ‘(||)’, namely ‘CmpNat 2 n ~ 'EQ’
In the first argument of ‘(&&)’, namely
‘(CmpNat 2 n ~ 'EQ || CmpNat 2 n ~ 'LT)’
In the first argument of ‘If’, namely
‘((CmpNat 2 n ~ 'EQ || CmpNat 2 n ~ 'LT)
&& (CmpNat n 16 ~ 'EQ || CmpNat n 16 ~ 'LT))’
|
13 | , If ((CmpNat 2 n ~ 'EQ || CmpNat 2 n ~ 'LT) && (CmpNat n 16 ~ 'EQ || CmpNat n 16 ~ 'LT))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
把约束简化一点,也可以写得更简洁:
CmpNat 1 n ~ 'LT && CmpNat n 17 ~ 'LT
但 GHC 仍然不喜欢那样,出于与以前相同的原因给出相同的类型错误。
在这种情况下,使用 CmpNat
而不是 <=?
的最简洁方法是什么?
CmpNat 2 n ~ 'EQ
是一个 约束 ,不是布尔值。
Prelude> :k 'EQ ~ 'EQ
'EQ ~ 'EQ :: Constraint
基本上,约束只能被证明,不能被证明,因此不能在 If
语句中使用。
(“永远不会为假”的平等感似乎很愚蠢,但实际上这种事情有充分的理由。比较布尔值与命题 在 Coq.)
你想要的是 CmpNat 2 n <a href="https://hackage.haskell.org/package/base-4.14.1.0/docs/Data-Type-Equality.html#t:-61--61-" rel="noreferrer">==</a> 'EQ`
.
Prelude Data.Type.Equality> :k 'EQ == 'EQ
'EQ == 'EQ :: Bool
我有以下类型:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.Kind
import GHC.TypeLits
import Data.Type.Bool
type family Valid (n :: Nat) :: Constraint where
Valid (n :: Nat) = ( KnownNat n
, If (2 <=? n && n <=? 16)
(() :: Constraint)
(TypeError ('Text "No Good"))
)
这按预期工作。但是 GHC 有一个 note,<=?
可能会被 CmpNat
取代。到目前为止,我尝试用 CmpNat
替换 <=?
的使用失败了。例如这个版本:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.Kind
import GHC.TypeLits
import Data.Type.Bool
type family Valid (n :: Nat) :: Constraint where
Valid (n :: Nat) = ( KnownNat n
, If ((CmpNat 2 n ~ 'EQ || CmpNat 2 n ~ 'LT) && (CmpNat n 16 ~ 'EQ || CmpNat n 16 ~ 'LT))
(() :: Constraint)
(TypeError ('Text "No Good"))
)
不仅更冗长,GHC 理所当然地不喜欢它,因为类型级布尔值 and/or 的组成部分本身不再是布尔值:
• Expected kind ‘Bool’,
but ‘CmpNat 2 n ~ 'EQ’ has kind ‘Constraint’
• In the first argument of ‘(||)’, namely ‘CmpNat 2 n ~ 'EQ’
In the first argument of ‘(&&)’, namely
‘(CmpNat 2 n ~ 'EQ || CmpNat 2 n ~ 'LT)’
In the first argument of ‘If’, namely
‘((CmpNat 2 n ~ 'EQ || CmpNat 2 n ~ 'LT)
&& (CmpNat n 16 ~ 'EQ || CmpNat n 16 ~ 'LT))’
|
13 | , If ((CmpNat 2 n ~ 'EQ || CmpNat 2 n ~ 'LT) && (CmpNat n 16 ~ 'EQ || CmpNat n 16 ~ 'LT))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
把约束简化一点,也可以写得更简洁:
CmpNat 1 n ~ 'LT && CmpNat n 17 ~ 'LT
但 GHC 仍然不喜欢那样,出于与以前相同的原因给出相同的类型错误。
在这种情况下,使用 CmpNat
而不是 <=?
的最简洁方法是什么?
CmpNat 2 n ~ 'EQ
是一个 约束 ,不是布尔值。
Prelude> :k 'EQ ~ 'EQ
'EQ ~ 'EQ :: Constraint
基本上,约束只能被证明,不能被证明,因此不能在 If
语句中使用。
(“永远不会为假”的平等感似乎很愚蠢,但实际上这种事情有充分的理由。比较布尔值与命题 在 Coq.)
你想要的是 CmpNat 2 n <a href="https://hackage.haskell.org/package/base-4.14.1.0/docs/Data-Type-Equality.html#t:-61--61-" rel="noreferrer">==</a> 'EQ`
.
Prelude Data.Type.Equality> :k 'EQ == 'EQ
'EQ == 'EQ :: Bool