我正在尝试在LiquidHaskell case study on Lazy Queues
中进行第一次练习module Main where
main :: IO ()
main = putStrLn "hello"
{-@ type Nat = {v:Int | 0 <= v} @-}
{-@ die :: {v:String | false} -> a @-}
die x = error x
{-@ measure realSize @-}
realSize :: [a] -> Int
realSize [] = 0
realSize (_:xs) = 1 + realSize xs
{-@ data SList a = SL {
size :: Nat
, elems :: {v:[a] | realSize v = size}
}
@-}
data SList a = SL { size :: Int, elems :: [a]}
{-@ type NEList a = {v:SList a | 0 < size v} @-}
{-@ hd :: NEList a -> a @-}
hd (SL _ (x:_)) = x
hd _ = die "empty SList"
okList = SL 1 ["cat"]
okHd = hd okList
okHd
失败:
app/Main.hs:30:13-18: Error: Liquid Type Mismatch
Inferred type
VV : {VV : (SList [Char]) | VV == Main.okList}
not a subtype of Required type
VV : {VV : (SList [Char]) | 0 < size VV}
In Context
VV : {VV : (SList [Char]) | VV == Main.okList}
Main.okList
: (SList [Char])
从错误消息中,我很确定我没有向LH提供足够的信息,因为它知道&#34;知道&#34; okList
非空,但我无法弄清楚如何修复它。
我尝试用后置条件(?)明确告诉它:
{-@ okList :: NEList a @-}
okList = SL 1 ["cat"]
但这不起作用:
app/Main.hs:29:5: Error: Specified Type Does Not Refine Haskell Type for Main.okList
Haskell: Main.SList [GHC.Types.Char]
Liquid : forall a. Main.SList a
答案 0 :(得分:4)
您的精炼类型okList
不限制类型。它限制了尺寸,但将类型从String
扩展到a
。
更改
{-@ okList :: NEList a @-}
okList = SL 1 ["cat"]
到
{-@ okList :: NEList String @-}
okList = SL 1 ["cat"]
它会起作用。
我必须承认我不太了解liquidhaskell,所以下面的所有内容可能只是我的猜测:
您必须执行此操作的主要原因是您使用默认构造函数okList
分别定义SL
。精简类型的SList
仅承诺size v = realSize (elems v)
,在调用构造函数时检查列表的大小,与数字文字进行比较然后丢弃,而不是存储在(液体)类型级别。因此,当您向okList
提供hd
时,可用于推理的唯一信息是size v = realSize (elems v)
(来自精炼数据类型),size v >= 0
(size
定义为一个Nat
),hd
不知道它是否是正面的。
在hd okList
中,liquidhaskell可能无法评估表达式,并通过okList
替换Sl 1 ["cat"]
并获取有关大小的信息,因此只能根据推断的精确类型okList
(在本例中为SList String
)。一个证据是hd $ SL 1 ["cat"]
将无法使用精炼类型。