我正在从Haskell对C进行一些绑定,并尝试使用LiquidHaskell使它更安全。在LH类型注释中指定字节串的长度时遇到了麻烦。
我在LiquidHaskell中具有增强的ByteString类型,其中包括其长度:
{-@ type ByteString Blen = {v:B.ByteString | bslen v == Blen} @-}
运行Liquidhaskell时出现以下错误:
**** RESULT: UNSAFE ************************************************************
/home/t/liquidproblem/Main.hs:47:3-22: Error: Liquid Type Mismatch
47 | Bi.PS foreignPtr 0 l
^^^^^^^^^^^^^^^^^^^^
Inferred type
VV : {v : Data.ByteString.Internal.ByteString | 0 <= bslen v
&& bslen v == stringlen v}
not a subtype of Required type
VV : {VV : Data.ByteString.Internal.ByteString | bslen VV == l}
In Context
l : {l : GHC.Types.Int | l >= 0}
第47行是:
44 {-@ makeBs :: ForeignPtr Word8 -> l:NonNeg -> ByteString l @-}
45 makeBs :: F.ForeignPtr F.Word8 -> Int -> B.ByteString
46 makeBs foreignPtr l =
47 Bi.PS foreignPtr 0 l
(我知道这似乎是一个愚蠢的功能,但之所以加入了该功能,是因为调试过程是要分解出位并在它们上放LH注释,直到发现问题为止。)
相关进口是:
import qualified Data.ByteString.Internal as Bi
import qualified Data.ByteString as B
import qualified Foreign as F
LH NonNeg类型是
{-@ type NonNeg = {i:Int | i >= 0} @-}
答案 0 :(得分:1)
LiquidHaskell不知道ByteString
返回的makeBs
的长度为l
,并且无法从可用信息中证明这一点。
您会知道,因为您知道PS
构造函数的第三个参数是长度。因此,此时您有两个(或可能一个)选项:
PS
构造函数的了解,并给它一个注释,例如
{-@ Bi.PS :: _ -> _ -> l:NonNeg -> ByteString l @-}
。我尝试了一下,但效果不佳,因为PS
签名中存在内部GHC类型,LH似乎不太擅长处理。 YMMV。或者,您可以:PS
并用assume
标记自己的功能:{-@ assume makeBs :: ForeignPtr Word8 -> l:NonNeg -> ByteString l @-}
。当然,如果标记为assume
的函数变大,这会冒更大的风险-虽然看起来很傻,但是如果您选择这种方法,则可能希望保持makeBs
左右。