在 Liquid 中定义度量 Haskell

Defining measures in Liquid Haskell

这是一个计算给定列表中数字平均值的简单函数。

{-@ type NonZero = {v:Int | v/=0 } @-}

{-@ divide :: Int -> NonZero -> Int @-}
divide :: Int -> Int -> Int
divide n d = div n d

{-@ measure nonEmpty :: [a] -> Bool @-}
nonEmpty [] = False
nonEmpty _ = True

{-@ size :: xs:[a] -> {v:Nat | nonEmpty xs => v>0 } @-}
size :: [a] -> Int
size [] = 0
size (_:xs) = 1 + size xs

{-@ type NEList a = {v:[a] | nonEmpty v} @-}

{-@ avg :: NEList Int -> Int @-}
avg xs = divide (sum xs) (size xs)

遗憾的是这段代码没有类型检查。

但是如果我在定义函数后声明 nonEmpty 是一个度量,它会起作用:

{-@ type NonZero = {v:Int | v/=0 } @-}

{-@ divide :: Int -> NonZero -> Int @-}
divide :: Int -> Int -> Int
divide n d = div n d

{-@ nonEmpty :: [a] -> Bool @-}
nonEmpty [] = False
nonEmpty _ = True
{-@ measure nonEmpty @-}

{-@ size :: xs:[a] -> {v:Nat | nonEmpty xs => v>0 } @-}
size :: [a] -> Int
size [] = 0
size (_:xs) = 1 + size xs

{-@ type NEList a = {v:[a] | nonEmpty v} @-}

{-@ avg :: NEList Int -> Int @-}
avg xs = divide (sum xs) (size xs)

那么有人可以解释为什么会这样吗?

这是因为 LH 希望通过第二种语法(而不是第一种)来声明度量。然而,不幸的是,LH 目前 不会 给出第一个错误消息,它似乎只是默默地忽略度量定义(或者更确切地说,将其视为 "uninterpreted")。

我们将修复代码,以便在有实际定义时告诉您。

简而言之:这是我们语法选择的不幸结果,我深表歉意!