使用Liquid Haskell检查有效令牌

时间:2016-08-14 01:32:44

标签: haskell 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类型 - &gt; 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

谢谢!

1 个答案:

答案 0 :(得分:1)

这里有几个问题。

  1. 您尝试将currTime定义为度量,但措施应该是函数。这应该被LiquidHaskell标记为错误。

  2. 您可能在currTime采取措施之前已经注意到这一点,但您目前无法引用类型签名中的顶级定义。我们可以通过将currTime作为参数传递给isExpired,并通过向ValidToken类型添加参数来修复您的示例(这可能是您想要做的事情,因为有效性是令牌是关于某个时间戳)。这是我们演示页面上工作版本的link

  3. 最后,您当然可以重写代码以在getCurrentTime内使用isValid,但您可能需要更改ValidToken的定义,因为当前时间永远不会逃脱isValid {1}}。 Here's我该怎么做。

    我定义了一个&#34;未解释的&#34;衡量(无正文)名为valid并更改isExpired的类型以返回IO {v:Bool | ((Prop v) <=> (not (valid t)))}。不幸的是,LiquidHaskell无法验证isExpired的定义,因为我们还没有告诉它valid的含义。因此,我们必须assume isExpired的类型,使其成为我们可信计算基础的一部分。我对此感到满意,因为它是一个小功能,而且它是唯一需要假设的东西。