根据(maxBound :: Int)的运行时值进行类型约束

时间:2018-08-17 17:30:50

标签: haskell ghc type-families type-level-computation

我对类型级别的计算和类型族等非常陌生,我正在尝试制作一个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”。


我如何实现我的目标?我对解决上述方法和完全不同的方法都开放。

1 个答案:

答案 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.