-
Notifications
You must be signed in to change notification settings - Fork 139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incompleteness with a top-level higher-order function #2440
Comments
Removing the type signature of compareSelf or giving it a polimorphic type also makes verification succeed. compareSelf :: (a -> a -> b) -> a -> b The error says
Using
where I'm guessing there is a bug here where |
Ah, I did not think to remove the main type signature. It seems that the {-# OPTIONS_GHC -fplugin=LiquidHaskell #-}
{-@ LIQUID "--higherorder" @-}
module HigherOrder where
{-@ boolEq :: a:Bool -> b:Bool -> { v:Bool | v <=> ((a && b) || (not a && not b)) } @-}
boolEq :: Bool -> Bool -> Bool
boolEq a b = (a && b) || (not a && not b)
-- This example successfully typechecks.
{-@ example1 :: Bool -> { v:Bool | v } @-}
example1 :: Bool -> Bool
example1 a = cself boolEq a
where
-- This function is identical to 'compareSelf'.
cself f x = f x x
{-@ compareSelf :: f:(Bool -> Bool -> Bool) -> x:Bool -> {v:Bool | v <=> f x x} @-}
compareSelf :: (Bool -> Bool -> Bool) -> Bool -> Bool
compareSelf f x = f x x
-- This example fails to typecheck. It can be made to typecheck by
-- removing the type signature and refinement annotation from the
-- 'compareSelf' definition.
{-@ example2 :: Bool -> { v:Bool | v } @-}
example2 :: Bool -> Bool
example2 a = compareSelf boolEq a Just as with the previous example,
As you suggested, if I remove the type signature and refinement annotation on |
Here's an example in which removing the type signature does not help. It's the same as the previous example, except that I use {-# OPTIONS_GHC -fplugin=LiquidHaskell #-}
-- Required for the signatures of 'compareNotSelf'.
{-# LANGUAGE RankNTypes #-}
{-@ LIQUID "--higherorder" @-}
module HigherOrder where
-- Try any combination of the signatures for 'compareNotSelf': no
-- signature, only normal type, only refinement type, or both
-- signatures. Note that the normal type requires RankNTypes, and the
-- refinement type requires the "--higherorder" flag.
{-@ compareNotSelf :: forall a. f:(Bool -> Bool -> a) -> x:Bool -> { v:a | v == f (not x) (not x) } @-}
compareNotSelf :: forall a. (Bool -> Bool -> a) -> Bool -> a
compareNotSelf f x = f (not x) (not x)
-- Examples that use (==)
{-@ example1a :: Bool -> { v:Bool | v } @-}
example1a :: Bool -> Bool
example1a a =
compareNotSelf (==) a
{-@ example1b :: Bool -> { v:Bool | v } @-}
example1b :: Bool -> Bool
example1b a =
cnself (==) a
where
-- 'cnself' is identical to 'compareNotSelf'
cnself f x = f (not x) (not x)
-- Examples that do not use (==)
{-@ boolEq :: b1:Bool -> b2:Bool -> { v:Bool | v <=> ((b1 && b2) || (not b1 && not b2)) } @-}
boolEq :: Bool -> Bool -> Bool
boolEq b1 b2 =
(b1 && b2) || (not b1 && not b2)
{-@ example2a :: Bool -> { v:Bool | v } @-}
example2a :: Bool -> Bool
example2a a =
compareNotSelf boolEq a
{-@ example2b :: Bool -> { v:Bool | v } @-}
example2b :: Bool -> Bool
example2b a =
cnself boolEq a
where
cnself f x = f (not x) (not x) Here, On the other hand, With
Without
|
The issue is the monomorphic signature, polymorphic variables not only carry types but also refinement information, I think you need abstract refinements |
Hello, I'm exploring what I can or can't do with higher-order functions. Is there a straightforward way to get the following failing example to typecheck?
It seems that defining a higher-order function at the top level, vs. in a
where
-clause, changes what can be proven about it.I used liquidhaskell-9.10.1 for these examples.
First, a working example
The following example typechecks.
compareSelf
is a function that takes another function as its first argument.The
example1
function returnsTrue
if itsInt
argument is equal to itself. Of course this is always the case, and Liquid Haskell agrees.The failing example
This example is identical to the first, except that I moved
compareSelf
out of thewhere
-clause and into a top-level definition.This change causes Liquid Haskell to return
UNSAFE
.Annotation did not fix it
I tried adding a refinement annotation to
compareSelf
, and noticed that this required me to use the--higherorder
flag.Adding this annotation changed an inferred type, but did not fix the
UNSAFE
result.Is there an extra annotation or flag I can use to make this example typecheck? Or should I generally avoid defining higher-order functions at top-level?
Thanks!
The text was updated successfully, but these errors were encountered: