我试图为Data.Ratio
模块编写一些规范。到目前为止,我有:
module spec Data.Ratio where
import GHC.Real
Data.Ratio.denominator :: GHC.Real.Integral a => r : GHC.Real.Ratio a -> {x:a | x > 0}
我验证的代码是:
{-@ die :: {v:String | false} -> a @-}
die msg = error msg
main :: IO ()
main = do
let x = 3 % 5
print $ denominator x
if denominator x < 0
then die "bad ending"
else putStrLn "good ending"
判断代码是安全的,因为分母永远不会返回负值。
我发现这很奇怪,因为我可能刚刚写了x <= 0
作为后置条件,根据Data.Ratio
模块的文档是不可能的。显然,Liquid Haskell并没有将我的后置条件与denominator
的实现进行比较。
我的理解是,由于未检查函数实现,我最好使用assume关键字:
assume Data.Ratio.denominator :: GHC.Real.Integral a => r : GHC.Real.Ratio a -> {x:a | x > 0}
然而,我得到:
Error: Bad Type Specification assumed type GHC.Real.denominator :: (Ratio a) -> {VV : a | VV > 0} Sort Error in Refinement: {VV : a_a2kc | VV > 0} Unbound Symbol a_a2kc Perhaps you meant: papp5, papp3, papp4, head, papp2, papp7, papp6, papp1, tail because The sort a_a2kc is not numeric
我的问题是
assume
关键字,如果它通过与功能实现进行比较显然没有验证我的精炼类型的正确性吗?assume
关键字吗?a
突然不是数字?当我没有使用assume
?答案 0 :(得分:0)
不幸的是,'Numeric'字面意思是'Num',甚至不是它的子类。我们需要扩展LH以支持上面描述的形式的子类;我会为它创建一个问题,谢谢你指出!
现在,如果您将您的类型专门化,例如Int
或Integer
然后LH正确抛出错误:
import GHC.Real
{-@ assume denom :: r:GHC.Real.Ratio Int -> {x:Int | x >= 0} @-}
denom :: GHC.Real.Ratio Int -> Int
denom = denominator
{-@ die :: {v:String | false} -> a @-}
die msg = error msg
main :: IO ()
main = do
let x = 3 % 5
print $ denom x
if denom x <= 0
then die "bad ending"
else putStrLn "good ending"
http://goto.ucsd.edu:8090/index.html#?demo=permalink%2F1504739852_3583.hs
如果您输出类型x > 0
,那么它再次安全。
http://goto.ucsd.edu:8090/index.html#?demo=permalink%2F1504739907_3585.hs
再次感谢您指出Ratio
问题!