Is it possible to encode a generic "lift" function in Haskell? - haskell

I'm not the biggest fan of varargs, but I always thought both the applicative (f <$> x <*> y) and idiom ([i| f x y |]) styles have too many symbols. I usually prefer going the liftA2 f x y way, but I, too, think that A2 is a little ugly. From this question, I've learned it is possible to implement vararg functions in Haskell. This way, is it possible to use the same principle in order implement a lift function, such that:
lift f a b == pure f <*> a <*> b
I've tried replacing the + by <*> on the quoted code:
class Lift r where
lift :: a -> r
instance Lift a where
lift = id
instance (Lift r) => Lift (a -> r) where
lift x y = lift (x <*> y)
But I couldn't manage to get the types right...

Notice that you can chain any number of <*>, to get a function of the form
f (a0 -> .. -> an) -> (f a0 -> .. -> f an)
If we have the type a0 -> .. -> an and f a0 -> .. -> f an, we can compute f from this. We can encode this relation, and the most general type, as follows
class Lift a f b | a b -> f where
lift' :: f a -> b
As you may expect, the "recursive case" instance will simply apply <*> once, then recurse:
instance (a ~ a', f' ~ f, Lift as f rs, Applicative f)
=> Lift (a -> as) f (f' a' -> rs) where
lift' f a = lift' $ f <*> a
The base case is when there is no more function. Since you can't actually assert "a is not a function type", this relies on overlapping instances:
instance (f a ~ b) => Lift a f b where
lift' = id
Because of GHCs instance selection rules, the recursive case will always be selected, if possible.
Then the function you want is lift' . pure :
lift :: (Lift a f b, Applicative f) => a -> b
lift x = lift' (pure x)
This is where the functional dependency on Lift becomes very important. Since f is mentioned only in the context, this function would be ill-typed unless we can determine what f is knowing only a and b (which do appear in the right hand side of =>).
This requires several extensions:
{-# LANGUAGE
OverlappingInstances
, MultiParamTypeClasses
, UndecidableInstances
, FunctionalDependencies
, ScopedTypeVariables
, TypeFamilies
, FlexibleInstances
#-}
and, as usual with variadic functions in Haskell, normally the only way to select an instance is to give an explicit type signature.
lift (\x y z -> x * y + z) readLn readLn readLn :: IO Int
The way I have written it, GHC will happily accept lift which is polymorphic in the arguments to f (but not f itself).
lift (+) [1..5] [3..5] :: (Enum a, Num a) => [a]
Sometimes the context is sufficient to infer the correct type. Note that the argument type is again polymorphic.
main = lift (\x y z -> x * y + z) readLn readLn readLn >>= print
As of GHC >= 7.10, OverlappingInstances has been deprecated and the compiler will issue a warning. It will likely be removed in some later version. This can be fixed by removing OverlappingInstances from the {-# LANGUAGE .. #-} pragma and changing the 2nd instance to
instance {-# OVERLAPS #-} (f a ~ b) => Lift a f b where

I assume you would prefer to use lift without type annotations. In this case there are basically two options:
First, if we use OverlappingInstances, polymorphic functions need annotations:
{-# LANGUAGE
OverlappingInstances,
MultiParamTypeClasses,
UndecidableInstances,
FunctionalDependencies,
FlexibleInstances,
TypeFamilies
#-}
import Control.Applicative
class Applicative f => ApN f a b | a b -> f where
apN :: f a -> b
instance (Applicative f, b ~ f a) => ApN f a b where
apN = id
instance (Applicative f, ApN f a' b', b ~ (f a -> b')) => ApN f (a -> a') b where
apN f fa = apN (f <*> fa)
lift :: ApN f a b => a -> b
lift a = apN (pure a)
-- Now we can't write "lift (+) (Just 0) Nothing"
-- We must annotate as follows:
-- lift ((+) :: Int -> Int -> Int) (Just 0) Nothing
-- Monomorphic functions work fine though:
-- lift (||) (Just True) (Just True) --> results in "Just True"
Second, if we instead use IncoherentInstances, lift will work without annotations even on polymorphic functions. However, some complicated stuff still won't check out, for example (lift . lift) (+) (Just (Just 0)) Nothing.
{-# LANGUAGE
IncoherentInstances, MultiParamTypeClasses,
UndecidableInstances,ScopedTypeVariables,
AllowAmbiguousTypes, FlexibleInstances, TypeFamilies
#-}
import Control.Applicative
class Applicative f => ApN f a b where
apN :: f a -> b
instance (Applicative f, b ~ f a) => ApN f a b where
apN = id
instance (Applicative f, ApN f a' b', b ~ (f a -> b')) => ApN f (a -> a') b where
apN f fa = apN (f <*> fa)
lift :: forall f a b. ApN f a b => a -> b
lift a = (apN :: f a -> b) (pure a)
-- now "lift (+) (Just 0) (Just 10)" works out of the box
I presented two solutions instead of just the one with IncoherentInstances because IncoherentInstances is a rather crude extension that should be avoided if possible. It's probably fine here, but I thought it worthwhile to provide an alternative solution, anyway.
In both cases I use the same trick to help inference and reduce annotations: I try to move information from the instance heads to the instance constraints. So instead of
instance (Applicative f) => ApN f a (f a) where
apN = id
I write
instance (Applicative f, b ~ f a) => ApN f a b where
apN = id
Also, in the other instance I use a plain b parameter in the instance head and add b ~ (f a ~ b') to the constraints.
The reason for doing this is that GHC first checks if there is a matching instance head, and it tries to resolve the constraints only after there is a successful match. We want to place the least amount of burden on the instance head, and let the constraint solver sort things out (because it's more flexible, can delay making judgements and can use constraints from other parts of the program).

Related

Quickcheck Applicative homomorphism law for Binary Tree

I am aware that the following question exists:
haskell - How to quickcheck applicative homomorphism property? - Stack Overflow
However, the introduction of the following PRAGMA
{-# LANGUAGE ScopedTypeVariables #-}
didn't solve my issue.
These are my definitions:
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Laws where
import Control.Applicative ((<$>), liftA3)
import Data.Monoid
import Test.QuickCheck
import Test.QuickCheck.Function
import Test.QuickCheck.Gen
data BinTree a = Empty | Node a (BinTree a) (BinTree a) deriving (Show, Eq)
instance Functor BinTree where
fmap _ Empty = Empty
fmap f (Node x hi hd) = Node (f x) (fmap f hi) (fmap f hd)
instance Applicative BinTree where
-- pure :: a -> BinTree a
pure x = Node x (pure x) (pure x)
-- <*> :: BinTree (a -> b) -> BinTree a -> BinTree b
_ <*> Empty = Empty -- L1,
Empty <*> t = Empty
(Node f l r) <*> (Node x l' r') = Node (f x) (l <*> l') (r <*> r')
instance (Arbitrary a) => Arbitrary (BinTree a) where
arbitrary = oneof [return Empty, -- oneof :: [Gen a] -> Gen a
liftA3 Node arbitrary arbitrary arbitrary]
-- Identity
apIdentityProp :: (Applicative f, Eq (f a)) => f a -> Bool
apIdentityProp v = (pure id <*> v) == v
-- pure f <*> pure x = pure (f x) -- Homomorphism
apHomomorphismProp :: forall f a b. (Applicative f, Eq (f b)) => Fun a b -> a -> Bool
apHomomorphismProp (apply -> g) x = (((pure g :: f (a -> b)) <*> (pure x :: f a)) :: f b) == (pure (g x) :: f b)
main :: IO ()
main = quickCheck (apHomomorphismProp :: Fun Int Int -> Int -> Bool)
How can I fix the following error ?
Could not deduce (Applicative f0)
from the context: (Applicative f, Eq (f b))
It would have been easier to analyse the problem if you had included the full error message, which mentions an ambiguous type variable. The thing that GHC is complaining about is that f does not appear anywhere in the type signature of apHomomorphismProp, except in the quantifier and constraints.
Why is that a problem? Well, it isn't a problem... but it used to be in older Haskell versions, because there was no way for the compiler to tell when you're using apHomomorphismProp what applicative it's supposed to test here. In fact this is still the case with the way you are using it: apHomomorphismProp :: Fun Int Int -> Int -> Bool does not mention BinTree in any way, so how is the compiler supposed to know that's what you mean? For all it knows, you could as well be asking for, say, the Maybe applicative to be tested here.
The solution, in modern Haskell, is -XTypeApplications, which just lets you explicitly say what a type variable should be instantiated with.
{-# LANGUAGE TypeApplications #-}
main = quickCheck (apHomomorphismProp #BinTree :: Fun Int Int -> Int -> Bool)
In fact I would recommend also using this syntax to clarify the Int types:
main = quickCheck $ apHomomorphismProp #BinTree #Int #Int
However, there was still the compiler error with apHomomorphismProp, which is all because prior to TypeApplications, a signature like the one you gave to apHomomorphismProp was useless. But this restriction is now obsolete†, and it can be disabled with -XAllowAmbiguousTypes:
{-# LANGUAGE ScopedTypeVariables, UnicodeSyntax, AllowAmbiguousTypes, TypeApplications #-}
apHomomorphismProp :: ∀ f a b. (Applicative f, Eq (f b)) => Fun a b -> a -> Bool
apHomomorphismProp (apply -> g) x = (pure #f g <*> pure x) == pure (g x)
Note that I only need to mention #f for one of the pures, the other ones are automatically constrained to the same applicative.
†It's arguable whether it's really obsolete. What's probably still true is that if a beginner gives their function an ambiguous type, it's more likely a mistake that should be caught right there and then, rather than something that's actually intended for use with -XTypeApplications. An unintentionally ambiguous type can cause quite confusing errors further down the line.

Writing a generic functor instance across type constructors?

I'm learning basic type classes and have written my own implementation of functor for my type Test a (behaves just like Maybe):
data Test a = Test a | Emp
class FC c a where
t :: (a -> b) -> c a -> c b
instance FC Test a where
t f (Test a) = Test (f a)
t f (Emp) = Emp
instance FC Maybe a where
t f (Just a) = Just (f a)
t f (Nothing) = Nothing
Is it possible to implement something like:
instance FC c where
t f (c v) = c (f v)
Error:
Parse error in pattern: c
In other words, abstract away the type constructor, replace with c and v, therefore creating a general instance that can be applied to any value with a context?
As you've learned, c a is not a syntactically valid pattern. But reading your question instead as a feature proposal: How would that work? Not every Functor has a single-element constructor which can be mapped over according to your pattern. Some examples:
data Pair a = Pair a a -- more than one element
instance Functor Pair where
fmap f (Pair x y) = Pair (f x) (f y)
data Proxy a = Proxy -- no elements
instance Functor Proxy where
fmap f Proxy = Proxy
newtype Cont r a = Cont { runCont :: (a -> r) -> r } -- element appears in a double-negative position
instance Functor (Cont r) where
fmap f (Cont g) = Cont (g . (. f))
In any case, I don't think the idea of a "generic instance" really makes sense. The instance is where you put your type-specific code. (It has to go somewhere!)
If you want to exert less effort in writing Functor instances you can use GHC's DeriveFunctor extension.
{-# LANGUAGE DeriveFunctor #-}
data Pair a = Pair a a deriving Functor
data Proxy a = Proxy deriving Functor
newtype Cont r a = Cont { runCont :: (a -> r) -> r } deriving Functor
You can do something very generic using GHC.Generic. Here is an incomplete example for a generic FC class definition (this is exactly what the generic-deriving package does):
First some extensions and importing the generics machinery
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeOperators #-}
import GHC.Generics
Then we define a class which mirrors your FC but we only have instances for the generic types
class GFC c where
gt :: (a -> b) -> c a -> c b
-- Constructors without arguments (Empty)
instance GFC U1 where
gt _ U1 = U1
-- Constructors where the parameter appears (Test a)
instance GFC Par1 where
gt f (Par1 a) = Par1 (f a)
-- Sums (| in datatype definitions)
instance (GFC f, GFC g) => GFC (f :+: g) where
gt f (L1 a) = L1 (gt f a)
gt f (R1 a) = R1 (gt f a)
-- Meta information wrapper
instance GFC f => GFC (M1 i c f) where
gt f (M1 a) = M1 (gt f a)
-- ... the rest of the instances for the generic types here.
-- But these 4 instances are all that is needed for your `Test` type.
Then you can have a default implementation for FC based on the above "generic" FC:
class FC c where
t :: (a -> b) -> c a -> c b
default -- DefaultSignatures allows us to do this
t :: (Generic1 c, GFC (Rep1 c)) => (a -> b) -> c a -> c b
t f = to1 . gt f . from1
-- turn something with Generic1 into its generic representation,
-- use the generic `gt` and then turn it back into its actual
-- representation
data Test a = Test a | Empty
deriving (Generic1, Show)
instance FC Test
And it works:
GHCI> t (==0) (Test (1 :: Int))
Test False
As far as I know this is not possible, simply because there can be multiple constructors and it is unknown whether a generic constructor Foo can take any attribute as type.
Say for instance you have a type called:
data Foo a = Bar Int | Qux a
Now it means you cannot abstract away the constructor. As long as it is Qux, there is no problem, but Bar always expects an Int and thus will error. Since you here define an instance over any kind of c, there will be cases where this does not work. Note furthermore that the c in your instance declaration has nothing to do with the c in your definition of t. In other words: constructors can imply type constraints so you cannot simply factor them out.
A remark on your question is that you can generalize both you class defintion and instance:
class FC c where
t :: (a -> b) -> c a -> c b
instance FC Test where
t f (Test a) = Test (f a)
t f Emp = Emp
So you can remove the a in the class definition. This is not equivalent with your questions since here you say that it can work for any a. Whereas when you define a class FC c a you can decide for which as you want implement an instance.

Might laziness also mean a value of function depends on context where it is called?

I'm trying to learn Haskell, and whilst playing with applicative functors, one thing I found puzzles me.
Let's define following function g that returns some functor:
*Main> let g = pure (2*)
*Main> :t g
g :: (Num a, Applicative f) => f (a -> a)
Since a return type is some functor, I can use g as a parameter in both of these functions:
f1 :: (Num a) => [a -> a] -> a
f1 (g:[]) = g 3
f2 :: (Num a) => Maybe (a -> a) -> a
f2 (Just g) = g 4
But it means that a value the function g returns depends also on context in which will be evaluated! (It might be both List and Maybe.) Is this also a property of laziness? Because until now I was thinking about laziness in a way that a value is calculated when is needed, but it is already determined when it is defined (for g in let expression).
As #augustss said, it has nothing to do with laziness but rather the fact that you are working with a typeclass. To make this clearer, you can model typeclasses by explicitly passing along a record packing all the functions the class defines. This technique is called dictionary passing in case you want to look up more info about it.
We start with a few extensions.
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
And then give the record type packing the functions an Applicative is supposed to have (in practice you'd also have a field saying that f is a Functor but I omit it here for brevity).
data Applicative f =
Applicative { pure :: forall a. a -> f a
, app :: forall a b. f (a -> b) -> f a -> f b
}
And we can define your function g as taking a record saying that f is an Applicative and delivering the behaviour you were describing (I kept Num as a class constraint but, similarly, it could be translated to record passing).
g :: Num a => Applicative f -> f (a -> a)
g Applicative{..} = pure (2*)
Your two functions f1 and f2 are still valid definitions:
f1 :: Num a => [a -> a] -> a
f1 (g:[]) = g 3
f2 :: Num a => Maybe (a -> a) -> a
f2 (Just g) = g 4
Now, we want to apply them to g but there's an issue: g has a function type expecting an Applicative f record being passed. Well, we can define the [] and Maybe instances of Applicative:
applicativeList :: Applicative []
applicativeList =
Applicative { pure = (:[])
, app = \ fs as -> fs >>= \ f -> fmap f as
}
applicativeMaybe :: Applicative Maybe
applicativeMaybe =
Applicative { pure = Just
, app = \ fs as -> fs >>= \ f -> fmap f as
}
And we then have to pick the right one for the application to typecheck ([] for f1 and Maybe for f2):
f1g = f1 (g applicativeList)
f2g = f2 (g applicativeMaybe)

Datatype-generic programming and the mysterious gdmXXX

I'm using datatype-generic programming for a class called Generic that contains a method called get. If my end user defines a type and forgets to add deriving Generic, and calls put, they will see an error message such as this:
No instance for (ALife.Creatur.Genetics.Code.BRGCWord8.GGene
(GHC.Generics.Rep ClassifierGene))
arising from a use of `ALife.Creatur.Genetics.Code.BRGCWord8.$gdmput'
I can tell users how to fix the error, but I am curious about this $gdmput. I assume it's a function or symbol that's automatically generated, but by what? Is it the use of the DefaultSignatures pragma, or the DeriveGeneric pragma? I read a few papers about datatype-generic programming, but did not see any reference to gdmXXX symbols.
Here's the definition of the Generic class.
{-# LANGUAGE TypeFamilies, FlexibleContexts, FlexibleInstances,
DefaultSignatures, DeriveGeneric, TypeOperators #-}
. . .
-- | A class representing anything which is represented in, and
-- determined by, an agent's genome.
-- This might include traits, parameters, "organs" (components of
-- agents), or even entire agents.
-- Instances of this class can be thought of as genes, i.e.,
-- instructions for building an agent.
class Genetic g where
-- | Writes a gene to a sequence.
put :: g -> Writer ()
default put :: (Generic g, GGenetic (Rep g)) => g -> Writer ()
put = gput . from
-- | Reads the next gene in a sequence.
get :: Reader (Either [String] g)
default get :: (Generic g, GGenetic (Rep g)) => Reader (Either [String] g)
get = do
a <- gget
return $ fmap to a
getWithDefault :: g -> Reader g
getWithDefault d = fmap (fromEither d) get
class GGenetic f where
gput :: f a -> Writer ()
gget :: Reader (Either [String] (f a))
-- | Unit: used for constructors without arguments
instance GGenetic U1 where
gput U1 = return ()
gget = return (Right U1)
-- | Constants, additional parameters and recursion of kind *
instance (GGenetic a, GGenetic b) => GGenetic (a :*: b) where
gput (a :*: b) = gput a >> gput b
gget = do
a <- gget
b <- gget
return $ (:*:) <$> a <*> b
-- | Meta-information (constructor names, etc.)
instance (GGenetic a, GGenetic b) => GGenetic (a :+: b) where
gput (L1 x) = putRawWord16 0 >> gput x
gput (R1 x) = putRawWord16 1 >> gput x
gget = do
a <- getRawWord16
case a of
Right x -> do
if even x -- Only care about the last bit
then fmap (fmap L1) gget
else fmap (fmap R1) gget
Left s -> return $ Left s
-- | Sums: encode choice between constructors
instance (GGenetic a) => GGenetic (M1 i c a) where
gput (M1 x) = gput x
gget = fmap (fmap M1) gget
-- | Products: encode multiple arguments to constructors
instance (Genetic a) => GGenetic (K1 i a) where
gput (K1 x) = put x
gget = do
a <- get
return $ fmap K1 a
The $gdm comes from DefaultSignatures. Here's a minimal example that produces a similar error message
{-# LANGUAGE DefaultSignatures #-}
data NoInstances = NoInstances
class Display a where
display :: a -> String
default display :: Show a => a -> String
display = show
instance Display NoInstances
The error message produced is
defaultsignatures.hs:11:10:
No instance for (Show NoInstances)
arising from a use of `Main.$gdmdisplay'
In the expression: Main.$gdmdisplay
In an equation for `display': display = Main.$gdmdisplay
In the instance declaration for `Display NoInstances'

Making (a, a) a Functor

How can I make (a, a) a Functor without resorting to a newtype?
Basically I want it to work like this:
instance Functor (a, a) where
fmap f (x, y) = (f x, f y)
But of course that's not a legal way to express it:
Kind mis-match
The first argument of `Functor' should have kind `* -> *',
but `(a, a)' has kind `*'
In the instance declaration for `Functor (a, a)'
What I really want is a type-level function like this: \a -> (a, a) (invalid syntax). So a type alias, perhaps?
type V2 a = (a, a)
instance Functor V2 where
fmap f (x, y) = (f x, f y)
I would think this would work, but it doesn't. First I get this complaint:
Illegal instance declaration for `Functor V2'
(All instance types must be of the form (T t1 ... tn)
where T is not a synonym.
Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Functor V2'
If I follow the advice and add the TypeSynonymInstances extension, I get a new error:
Type synonym `V2' should have 1 argument, but has been given 0
In the instance declaration for `Functor V2'
Well, duh, that's the point! V2 has kind * -> * which is what is required of a Functor instance. Well, ok, I can use a newtype like this:
newtype V2 a = V2 (a, a)
instance Functor V2 where
fmap f (V2 (x, y)) = V2 (f x, f y)
But now I've got to sprinkle V2s liberally throughout my code instead of just being able to deal with simple tuples, which kind of defeats the point of making it a Functor; at that point I might as well make my own function vmap :: (a -> b) -> (a, a) -> (b, b).
So is there any way to do this nicely, i.e. without a newtype?
As others have stated, there's no way to do this without resorting to newtypes or data declarations. However, have you looked at Control.Arrow? Many of those functions are very useful with tuples, for example:
vmap :: (a -> b) -> (a,a) -> (b,b)
vmap f = f *** f
You can declare
instance Functor ((,) a) where
...
However that doesn't constrain the first element of your pair, and fmap would only act on the second element.
The issue is that a tuple doesn't enforce a relationship between the types of the two elements.
If you don't want a newtype decorator you can make your own fresh type:
data Pair a = P a a
instance Functor Pair where
...
which will be easier to work with than a newtype around a tuple.
With singletons you can define a Functor type class for defunctionalized symbols (Type ~> Type instead of Type -> Type)
{-# Language ExplicitNamespaces, TypeApplications, TypeOperators, KindSignatures, ScopedTypeVariables, DataKinds, TypeInType, TypeFamilies, AllowAmbiguousTypes, InstanceSigs #-}
import Data.Kind (Type)
import Data.Singletons (type (~>), Apply)
class Functor' (f :: Type ~> Type) where
fmap' :: (a -> a') -> (Apply f a -> Apply f a')
data Dup :: Type ~> Type
type instance Dup `Apply` a = (a, a)
instance Functor' Dup where
fmap' :: (a -> a') -> ((a, a) -> (a', a'))
fmap' f (a1, a2) = (f a1, f a2)
This gives you a Prelude.Functor instance automatically
newtype f $ a = App (Apply f a)
instance Functor' f => Functor (($) f) where
fmap :: (a -> a') -> (f $ a -> f $ a')
fmap f (App fa) = App (fmap' #f f fa)

Resources