我对类型级别的计算和类型族等非常陌生,我正在尝试制作一个Constraint
,以防止类型级别Nat
超过{{1 }}。
为了对代码进行将来的验证,我希望找到一种解决方案,无论是正常地还是编译为具有不同字长的计算机,该解决方案都能正常工作。它应在运行时根据maxBound :: Int
的 目标计算机的 值来限制Nat
(如果有一种方法可以在编译时获取该确切值,时间,然后从那里走,就可以了。
我在学习如何使用编译器错误消息进行约束时获得了一些帮助,这是我解决该问题的不太好尝试:
maxBound :: Int
它抱怨type family BigUpperLimit (n :: Nat) (c :: Constraint) :: Constraint where
BigUpperLimit n c = If (CmpNat n (maxBound :: Int) == 'GT)
(TypeError ( Text "UInt "
:<>: ShowType n
:<>: Text " exceeds UInt "
:<>: ShowType (maxBound :: Int)
:<>: Text ", the maximum size allowed with this machine's word size."
)
)
c
不是已知的类型变量。如果我在maxBound
前面放一个'
,它会抱怨“类型非法升级的术语变量:maxBound”。
我如何实现我的目标?我对解决上述方法和完全不同的方法都开放。
答案 0 :(得分:0)
我认为最好的办法是在这里使用 CPP 本身。
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
import GHC.TypeLits
import Data.Type.Bool
import Data.Kind
#include "MachDeps.h"
type family BigUpperLimit (n :: Nat) :: Constraint where
BigUpperLimit n = ( KnownNat n
, If (0 <=? n && n <=? WORD_SIZE_IN_BITS)
(() :: Constraint)
(TypeError ( Text "UInt "
:<>: ShowType n
:<>: Text " exceeds UInt "
:<>: ShowType WORD_SIZE_IN_BITS
:<>: Text ", the maximum size allowed with this machine's word size.")))
现在您可以:
*Main> 2 :: BigUpperLimit 12 => Int
2
*Main> 2 :: BigUpperLimit 120 => Int
<interactive>:34:1: error:
• UInt 120 exceeds UInt 64, the maximum size allowed with this machine's word size.
• In the expression: 2 :: BigUpperLimit 120 => Int
In an equation for ‘it’: it = 2 :: BigUpperLimit 120 => Int
注意后者是一个类型错误:
*Main> :t 2 :: BigUpperLimit 120 => Int
<interactive>:1:1: error:
UInt 120 exceeds UInt 64, the maximum size allowed with this machine's word size.