Reputation: 71
I am encoding (as an assumption) the functor identity law like so:
...
import qualified Prelude ()
...
{-@ class Functor f where
fmap :: forall a b. (a -> b) -> (f a -> f b) @-}
class Functor f where
fmap :: (a -> b) -> (f a -> f b)
-- identity function
{-@ id :: forall a . x : a -> {y : a | x = y} @-}
id :: forall a . a -> a
id x = x
-- functor law: mapping with identity is identity
{-@ assume
fmap_id :: forall f a . Functor f => x : f a ->
{fmap id x = id x} @-}
fmap_id :: Functor f => f a -> ()
fmap_id _ = ()
I can't see anything wrong with this formulation, yet I get this error from LH:
src/Category/Functor/LH.hs:45:16: error:
• Illegal type specification for `Category.Functor.LH.fmap_id`
Category.Functor.LH.fmap_id :: forall f a .
(Functor<[]> f) =>
x:f a -> {VV : () | Category.Functor.LH.fmap Category.Functor.LH.id x == Category.Functor.LH.id x}
Sort Error in Refinement: {VV : Tuple | Category.Functor.LH.fmap Category.Functor.LH.id x == Category.Functor.LH.id x}
Unbound symbol Category.Functor.LH.fmap --- perhaps you meant: Category.Functor.LH.C:Functor ?
•
|
45 | fmap_id :: forall f a . Functor f => x : f a ->
|
What am I doing wrong? My goal is to formulate this point-free with extensionality, but at least this point-wise formulation should work first.
Configuration:
Upvotes: 0
Views: 139
Reputation: 584
Support for typeclasses is not yet supported in the official release of Liquid Haskell (although it is almost ready to merge). For now, you can use this fork which implements typeclass support. After recursively cloning the repository, you can install the forked version with:
pushd liquid-benchmark/liquidhaskell
stack install
popd
We define Functor
and its laws (in the VFunctor
subclass) in liquid-base/liquid-base/src/Data/Functor/Classes.hs
as follows. Notice that you can specify refinements on the typeclass methods directly.
class Functor f where
{-@ fmap :: forall a b. (a -> b) -> f a -> f b @-}
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
class Functor m => VFunctor m where
{-@ lawFunctorId :: forall a . x:m a -> {fmap id x == id x} @-}
lawFunctorId :: m a -> ()
{-@ lawFunctorComposition :: forall a b c . f:(b -> c) -> g:(a -> b) -> x:m a -> { fmap (compose f g) x == compose (fmap f) (fmap g) x } @-}
lawFunctorComposition :: forall a b c. (b -> c) -> (a -> b) -> m a -> ()
You can run the forked version of Liquid Haskell on the typeclass definitions with:
liquid --typeclass -i liquid-base/liquid-base/src/ liquid-base/liquid-base/src/Data/Functor/Classes.hs
We create a verified Maybe
instance in liquid-base/liquid-base/src/Data/Maybe/Functor.hs
with:
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just x) = Just (f x)
_ <$ Nothing = Nothing
x <$ (Just _) = Just x
instance VFunctor Maybe where
lawFunctorId Nothing = ()
lawFunctorId (Just _) = ()
lawFunctorComposition f g Nothing = ()
lawFunctorComposition f g (Just x) = ()
You can run Liquid Haskell on the Maybe
instance to verify that it satisfies the required laws:
liquid --typeclass -i liquid-base/liquid-base/src/ liquid-base/liquid-base/src/Data/Maybe/Functor.hs
Upvotes: 2