使用 Liquid Haskell 检查有效令牌
Using Liquid Haskell to Check for Valid Tokens
我正在使用 liquid-haskell 做一些实验,看看我可以用它做些什么,但我遇到了一些困难。基本思想是我有一些功能需要访问令牌,该令牌会在经过一定时间后过期。我正在尝试查看如何使用 liquid-haskell 来确保在将令牌传递到我的函数之一之前检查令牌的有效性。我在下面创建了一个最小的工作版本来演示我的问题。当我在这个文件上 运行 liquid 时,我得到以下错误:
/tmp/liquidTest.hs:18:17-42: Error: Liquid Type Mismatch
18 | isExpired tok = currTime >= expiration tok
^^^^^^^^^^^^^^^^^^^^^^^^^^
Inferred type
VV : {VV : GHC.Types.Bool | Prop VV <=> Main.currTime >= ?a}
not a subtype of Required type
VV : {VV : GHC.Types.Bool | Prop VV <=> currTime >= expiration tok}
In Context
Main.currTime := Data.Time.Clock.UTC.UTCTime
tok := Main.Token
?a := {?a : Data.Time.Clock.UTC.UTCTime | ?a == expiration tok}
我似乎无法弄清楚为什么会出现此错误,而且我尝试的一切都失败了。有人可以帮我吗?
此外,我想将 currTime 函数替换为 time 包中的 getCurrentTime 函数。这样我就可以将令牌上的时间戳与当前时间进行比较。这意味着我的 isExpired 函数的类型为 Token -> IO Bool。甚至可以使用液体 haskell?
import Data.Time
import Language.Haskell.Liquid.Prelude
{-@ data Token = Token
(expiration :: UTCTime)
@-}
data Token = Token
{ expiration :: UTCTime
} deriving Show
{-@ measure currTime :: UTCTime @-}
currTime :: UTCTime
currTime = UTCTime (ModifiedJulianDay 57614) 83924.978297
{-@ isExpired :: t:Token -> {v:Bool | ((Prop v) <=> (currTime >= expiration t))} @-}
isExpired :: Token -> Bool
isExpired tok = currTime >= expiration tok
{-@ type ValidToken = {t:Token | currTime < expiration t} @-}
{-@ showToken :: ValidToken -> String @-}
showToken :: Token -> String
showToken tok = show tok
main :: IO ()
main = do
ct <- getCurrentTime
let tok = Token ct
print currTime
case isExpired tok of
True -> putStrLn "The token has expired!"
False -> putStrLn $ showToken tok
谢谢!
这里有几个问题。
您试图将 currTime
定义为度量,但度量应该是函数。这应该被 LiquidHaskell 标记为错误。
您在制定 currTime
措施之前可能已经注意到这一点,但您目前无法在类型签名中引用顶级定义。我们可以通过将 currTime
作为参数传递给 isExpired
并向 ValidToken
类型添加一个参数来修复您的示例(这可能是您想要做的,因为token 是关于某个时间戳的)。这是我们演示页面上工作版本的link。
最后,您当然可以重写代码以在 isValid
中使用 getCurrentTime
,但您可能需要更改 ValidToken
的定义,因为当前时间永远不会逃脱 isValid
。 Here's 我会怎么做。
我定义了一个名为 valid
的 "uninterpreted" 度量(无正文)并将 isExpired
的类型更改为 return IO {v:Bool | ((Prop v) <=> (not (valid t)))}
。不幸的是,LiquidHaskell 无法验证 isExpired
的定义,因为我们还没有告诉它 valid
是什么意思。所以我们必须 assume
isExpired
的类型,使其成为我们可信计算基础的一部分。我同意这个,因为它是一个小函数,而且是唯一需要假设的东西。
我正在使用 liquid-haskell 做一些实验,看看我可以用它做些什么,但我遇到了一些困难。基本思想是我有一些功能需要访问令牌,该令牌会在经过一定时间后过期。我正在尝试查看如何使用 liquid-haskell 来确保在将令牌传递到我的函数之一之前检查令牌的有效性。我在下面创建了一个最小的工作版本来演示我的问题。当我在这个文件上 运行 liquid 时,我得到以下错误:
/tmp/liquidTest.hs:18:17-42: Error: Liquid Type Mismatch
18 | isExpired tok = currTime >= expiration tok
^^^^^^^^^^^^^^^^^^^^^^^^^^
Inferred type
VV : {VV : GHC.Types.Bool | Prop VV <=> Main.currTime >= ?a}
not a subtype of Required type
VV : {VV : GHC.Types.Bool | Prop VV <=> currTime >= expiration tok}
In Context
Main.currTime := Data.Time.Clock.UTC.UTCTime
tok := Main.Token
?a := {?a : Data.Time.Clock.UTC.UTCTime | ?a == expiration tok}
我似乎无法弄清楚为什么会出现此错误,而且我尝试的一切都失败了。有人可以帮我吗?
此外,我想将 currTime 函数替换为 time 包中的 getCurrentTime 函数。这样我就可以将令牌上的时间戳与当前时间进行比较。这意味着我的 isExpired 函数的类型为 Token -> IO Bool。甚至可以使用液体 haskell?
import Data.Time
import Language.Haskell.Liquid.Prelude
{-@ data Token = Token
(expiration :: UTCTime)
@-}
data Token = Token
{ expiration :: UTCTime
} deriving Show
{-@ measure currTime :: UTCTime @-}
currTime :: UTCTime
currTime = UTCTime (ModifiedJulianDay 57614) 83924.978297
{-@ isExpired :: t:Token -> {v:Bool | ((Prop v) <=> (currTime >= expiration t))} @-}
isExpired :: Token -> Bool
isExpired tok = currTime >= expiration tok
{-@ type ValidToken = {t:Token | currTime < expiration t} @-}
{-@ showToken :: ValidToken -> String @-}
showToken :: Token -> String
showToken tok = show tok
main :: IO ()
main = do
ct <- getCurrentTime
let tok = Token ct
print currTime
case isExpired tok of
True -> putStrLn "The token has expired!"
False -> putStrLn $ showToken tok
谢谢!
这里有几个问题。
您试图将
currTime
定义为度量,但度量应该是函数。这应该被 LiquidHaskell 标记为错误。您在制定
currTime
措施之前可能已经注意到这一点,但您目前无法在类型签名中引用顶级定义。我们可以通过将currTime
作为参数传递给isExpired
并向ValidToken
类型添加一个参数来修复您的示例(这可能是您想要做的,因为token 是关于某个时间戳的)。这是我们演示页面上工作版本的link。
最后,您当然可以重写代码以在 isValid
中使用 getCurrentTime
,但您可能需要更改 ValidToken
的定义,因为当前时间永远不会逃脱 isValid
。 Here's 我会怎么做。
我定义了一个名为 valid
的 "uninterpreted" 度量(无正文)并将 isExpired
的类型更改为 return IO {v:Bool | ((Prop v) <=> (not (valid t)))}
。不幸的是,LiquidHaskell 无法验证 isExpired
的定义,因为我们还没有告诉它 valid
是什么意思。所以我们必须 assume
isExpired
的类型,使其成为我们可信计算基础的一部分。我同意这个,因为它是一个小函数,而且是唯一需要假设的东西。