On inferring fmap for ADTs - haskell

Suppose that two new types are defined like this
type MyProductType a = (FType1 a, FType2 a)
type MyCoproductType a = Either (FType1 a) (FType2 a)
...and that FType1 and Ftype2 are both instances of Functor.
If one now were to declare MyProductType and MyCoproductType as instances of Functor, would the compiler require explicit definitions for their respective fmap's, or can it infer these definitions from the previous ones?
Also, is the answer to this question implementation-dependent, or does it follow from the Haskell spec?
By way of background, this question was motivated by trying to make sense of a remark in something I'm reading. The author first defines
type Writer a = (a, String)
...and later writes (my emphasis)
...the Writer type constructor is functorial in a. We don't even have to implement fmap for it, because it's just a simple product type.
The emphasized text is the remark I'm trying to make sense of. I thought it meant that Haskell could infer fmap's for any ADT based on functorial types, and, in particular, it could infer the fmap for a "simple product type" like Writer, but now I think this interpretation is not right (at least if I'm reading Ørjan Johansen's answer correctly).
As for what the author meant by that sentence, now I really have no clue. Maybe all he meant is that it's not worth the trouble to re-define Writer in such a way that its functoriality can be made explicit, since it's such a "simple ... type". (Grasping at straws here.)

First, you cannot generally define new instances for type synonyms, especially not partially applied ones as you would need in your case. I think you meant to define a newtype or data instead:
newtype MyProductType a = MP (FType1 a, FType2 a)
newtype MyCoproductType a = MC (Either (FType1 a) (FType2 a))
Standard Haskell says nothing about deriving Functor automatically at all, that is only possible with GHC's DeriveFunctor extension. (Or sometimes GeneralizedNewtypeDeriving, but that doesn't apply in your examples because you're not using a just as the last argument inside the constructor.)
So let's try that:
{-# LANGUAGE DeriveFunctor #-}
data FType1 a = FType1 a deriving Functor
data FType2 a = FType2 a deriving Functor
newtype MyProductType a = MP (FType1 a, FType2 a) deriving Functor
newtype MyCoproductType a = MC (Either (FType1 a) (FType2 a)) deriving Functor
We get the error message:
Test.hs:6:76:
Can't make a derived instance of ‘Functor MyCoproductType’:
Constructor ‘MC’ must use the type variable only as the last argument of a data type
In the newtype declaration for ‘MyCoproductType’
It turns out that GHC can derive the first three, but not the last one. I believe the third one only works because tuples are special cased. Either doesn't work though, because GHC doesn't keep any special knowledge about how Either treats its first argument. It's nominally a mathematical functor in that argument, but not a Haskell Functor.
Note that GHC is smarter about using variables only as last argument of types known to be Functors. The following works fine:
newtype MyWrappedType a = MW (Either (FType1 Int) (FType2 (Maybe a))) deriving Functor
So to sum up: It depends, GHC has an extension for this but it's not always smart enough to do what you want.

Related

True isomorphisms in Haskell

Are the following assertions true:
The only real isomorphism, accessible programatically to the user, verified by Haskell type system, and that the Haskell compiler is/can be made aware of, is between:
the set of values of a Haskell datatype
the set of values of types those required by its constructors
Even generic programming can't produce "true" isomorphism, whose composition results at run time in an identity (thus staged-sop - and similarly in Ocaml)
Haskell itself is the only producing isomorphism, Coercible, but those isomorphism are restricted to the identity isomorphism
By "real isomorphism, accessible programatically to the user, verified by Haskell type system, and that the Haskell compiler is/can be made aware of" I mean a pair of function u : a -> b and v : b -> a such that Haskell knows (by being informed or otherwise) that u.v=id and v.u=id. Just like it knows (at compile time) how to rewrite some code to do "fold fusion", which is akin to, at once, recognize and apply it.
Look into Homotopy Type Theory/Cubical Agda where an "equality is isomorphism". I am not familiar enough with it to know what happens operationally, even if Agda knows isomorphic types are equal I still think your "true isomorphism" (i.e. with a proof and fusion) is too tall of an order.
In GHC it is possible to derive via "isomorphisms" but we need to wait for dependent types to properly verify isomorphisms in the type system. Even so they can be used to produce bone fide code even if you have to do some work operationally.
You already mentioned "representational equality" (Coercible) but it is worth discussing it. It underpins the two coerce-based deriving strategies: GeneralizedNewtypeDeriving and DerivingVia which generalizes GND.
GND is the simplest way to turn an isomorphism (Coercible USD Int) into code:
type USD :: Type
newtype USD = MkUSD Int
deriving
newtype (Eq, Ord, Show, Num)
Operationally coerce is zero-cost at so they incur no cost at run-time. This is the only way you will get what you want in Haskell.
Isomorphisms can also be done through user-defined type classes.
An instance of Representable f means f is (naturally) isomorphic to functions from its representing object (Rep f ->). The newtype Co uses this isomorphism to derive function instances for representable functor. A Pair a of two values is represented by Bool, and is thus isomorphic to Bool -> a.
This isomorphism lets Pair derive Functor, Applicative and Monad by roundtripping through (Bool ->):
type Pair :: Type -> Type
data Pair a = a :# a
deriving (Functor, Applicative, Monad)
via Co Pair
instance Distributive Pair where
distribute :: Functor f => f (Pair a) -> Pair (f a)
distribute = distributeRep
instance Representable Pair where
type Rep Pair = Bool
index :: Pair a -> (Bool -> a)
index (false :# true) = \case
False -> false
True -> true
tabulate :: (Bool -> a) -> Pair a
tabulate make = make False :# make True
When you derive Generic/Generic1 the compiler generates an isomorphism between a generic type and its generic representation Rep/Rep1 (not to be confused with the representing object Rep from the above example).
The class laws state that to/from and to1/from1 witness that isomorphism. The type system does not enforce these laws but if you derive them they should hold.
They are the main way to define generic implementations in Haskell. I recently introduced two newtypes Generically and Generically1 to base, as standard names for generic behaviour (use generic-data until the next GHC release). You can derive a generic isomorphism and programmatically use it in the next line without leaving the data declaration:
type Lists :: Type -> Type
data Lists a = Lists [a] [a] [a]
deriving
stock (Show, Generic, Generic1)
deriving (Semigroup, Monoid)
via Generically (Lists a)
deriving (Functor, Applicative, Alternative)
via Generically1 Lists
>> mempty #(Lists _)
Lists [] [] []
>> empty #Lists
Lists [] [] []
>> Lists "a" "b" "c" <> Lists "!" "." "?"
Lists "a!" "b." "c?"
>> pure #Lists 'a'
Lists "a" "a" "a"
You will however have to pay for the converstion cost, it's not as simple as adding {-# Rules "to/from" to . from = id #-} because the actual instances will appear with intermediate terms like to (from a <> from b). Even your "true isomorphisms" GHC could not fuse away the conversion since it's not of the form to . from.
There is also a library iso-deriving (blog) that allows deriving via arbitrary isomorphisms.

Can I tell GHC to arbitrarily select which instance to use, because I don't care?

I have some code like this:
{-# OPTIONS_GHC -Wall #-}
{-# LANUAGE VariousLanguageExtensionsNoneOfWhichWorked #-}
import Control.Applicative
import Data.Either
import Data.Void
class Constructive a where
lem :: Either (a -> Void) a
instance Constructive Void where
lem = Left id
instance Num a => Constructive a where
lem = Right 0
instance Enum a => Constructive a where
lem = Right $ toEnum 0
instance Bounded a => Constructive a where
lem = Right minBound
instance Monoid a => Constructive a where
lem = Right mempty
instance Alternative f => Constructive (f a) where
lem = Right empty
The problem is, GHC complains with
pad.hs:49:10:
Duplicate instance declarations:
instance [overlap ok] Bounded a => Constructive a
-- Defined at pad.hs:49:10
instance [overlap ok] Monoid a => Constructive a
-- Defined at pad.hs:52:10
Along with a bunch of similar errors.
Is there a way to tell GHC to pick one at random, since I don't care which it uses? (I don't even care if it picks a different one each time I use lem, since it does not matter.)
This is not really an answer to your question, more like an extended comment suggesting another route how to tackle the problem.
In Haskell the canonical solution would be to create a newtype for each of your instances, which is probably not what you want. However, I'd like to suggest you an alternative approach.
In Haskell we basically have 3 possibilities how to construct a data type:
Algebraic data types using products and coproducts (disjoint unions).
Function types.
Primitive types.
For the first part, we could use SYB or GHC Generics. If a product is empty, or has an empty factor, it maps to a -> Void. And a coproduct maps to a -> Void iff all its summands do.
A function type a -> b is constructive if both a and b are:
instance (Constructive a, Constructive b) => Constructive (a -> b) where
...
If x :: b is nonempty, a -> b is inhabited by const x. If a is empty then a -> b is inhabited by absurd. And if a is non-empty and b is empty, a -> b maps to Void.
All Haskell primitive types are non-empty, so they're trivially constructive.
Unfortunately it seems there is no way to tell GHC that all data types are one of these three. My suggestion would be to implement the instance for -> and then either
Try to use SYB to implement an instance for everything that implements Data. There would still be the problem how to deal with overlapping instances. Or:
Try to use GHC Generics to provide default instances for ADTs and implement instances manually for primitive types. This would mean that for every data type you'd have to still provide an empty instance implementation, with the default provided by Generics.
After writing this, I discovered AdvancedOverlap. Perhaps combining it with one of the previous approaches could lead to a nice solution.

How can I find out which (concrete) types satisfy a set of typeclass constraints?

Given a number of typeclass constraints:
{-# LANGUAGE ConstraintKinds, MultiParamTypeClasses #-}
import Data.Array.Unboxed(Ix,IArray,UArray)
type IntLike a = (Ord a, Num a, Enum a, Show a, Ix a, IArray UArray a)
How can I find out which types satisfy IntLike, i.e. all the mentioned constraints jointly?
I can puzzle together the information needed from the output of ghci's :info command, and then doublecheck my work by calling (or having ghci typecheck)
isIntLike :: IntLike -> Bool
isIntLike = const True
at various types, e.g. isIntLike (3::Int).
Is there a way to get ghci to do this for me?
I'm currently interested in concrete types, but wouldn't mind having a more general solution which also does clever stuff with unifying contexts!
Community Wiki answer based on the comments:
You can do this using template haskell.
main = print $(reify ''Show >>= stringE . show).
This won't work for type synonyms - rather, reify returns the AST representing the type synonym itself, without expanding it. You can check for type synonyms which are constraints, extract the constraints of which that type synonym consists, and continue reifying those.

Extensible Haskell Type Classes

I am reading a paper on dependently-typed programming and came across the following quote:
"[...] in contrast to Haskell's type classes, the data type [...] is closed", in the sense that one cannot add new types to the universe without extending the data type.
My newbie question is: in what sense are Haskell type classes open? How are they extensible? Also, what are the type-theoretical consequences of having this property (open vs closed)?
Thank you!
Type classes are open, because you can make arbitrary type an instance of it. When you create type class you specify interface, but not the types which belong to it. Then in any code which includes typeclass definition you can make your type instance of it providing necessary functions from interface using instance TypeClass type of syntax.
Given a type class like:
class Monoid m where
mempty :: m
mappend :: m -> m -> m
... it is (basically) implemented under the hood as a dictionary type:
data Monoid m = Monoid
{ mempty :: m
, mappend :: m -> m -> m
}
Instances like:
instance Monoid [a] where
mempty = []
mappend = (++)
... get translated to dictionaries:
listIsAMonoid :: Monoid [a]
listIsAMonoid = Monoid
{ mempty = []
, mappend = (++)
}
... and the compiler consults above dictionary whenever you use lists in their capacity as Monoids.
This brings us to your questions:
in what sense are Haskell type classes open? How are they extensible?
They are open in the same sense that polymorphic values are open. We have some polymorphic data type:
data Monoid m = ...
... and we can instantiate the polymorphic m type variable to any type where we can provide suitable values for the mempty and mappend fields.
Type classes are "open" because they can always have more types added to them "after the fact" by adding more instance declarations. This can even be done in "client" code that merely uses the module containing the type class.
The key point is that I can write code that operates on values with some type-class constraint, and that same code with no modification can be used on types that weren't in existence when I wrote the type class.
Concrete data types in Haskell are "closed" in that this cannot happen. If I write code that operates on members a specific data type (even if it's polymorphic), then there's no way you can use that code to operate on new kinds of thing I hadn't thought of unless you're able to modify the type (which then probably requires modifying all the places where it is used).

List of existentially quantified values in Haskell

I'm wondering why this piece of code doesn't type-check:
{-# LANGUAGE ScopedTypeVariables, Rank2Types, RankNTypes #-}
{-# OPTIONS -fglasgow-exts #-}
module Main where
foo :: [forall a. a]
foo = [1]
ghc complains:
Could not deduce (Num a) from the context ()
arising from the literal `1' at exist5.hs:7:7
Given that:
Prelude> :t 1
1 :: (Num t) => t
Prelude>
it seems that the (Num t) context can't match the () context of arg. The point I can't understand is that since () is more general than (Num t), the latter should and inclusion of the former. Has this anything to do with lack of Haskell support for sub-typing?
Thank you for any comment on this.
You're not using existential quantification here. You're using rank N types.
Here [forall a. a] means that every element must have every possible type (not any, every). So [undefined, undefined] would be a valid list of that type and that's basically it.
To expand on that a bit: if a list has type [forall a. a] that means that all the elements have type forall a. a. That means that any function that takes any kind of argument, can take an element of that list as argument. This is no longer true if you put in an element which has a more specific type than forall a. a, so you can't.
To get a list which can contain any type, you need to define your own list type with existential quantification. Like so:
data MyList = Nil | forall a. Cons a MyList
foo :: MyList
foo = Cons 1 Nil
Of course unless you restrain element types to at least instantiate Show, you can't do anything with a list of that type.
First, your example doesn't even get that far with me for the current GHC, because you need to enable ImpredecativeTypes as well. Doing so results in a warning that ImpredicativeTypes will be simplified or removed in the next GHC. So we're not in good territory here. Nonetheless, adding the proper Num constraint (foo :: [forall a. Num a => a]) does allow your example to compile.
Let's leave aside impredicative types and look at a simpler example:
data Foo = Foo (forall a. a)
foo = Foo 1
This also doesn't compile with the error Could not deduce (Num a) from the context ().
Why? Well, the type promises that you're going to give the Foo constructor something with the quality that for any type a, it produces an a. The only thing that satisfies this is bottom. An integer literal, on the other hand, promises that for any type a that is of class Num it produces an a. So the types are clearly incompatible. We can however pull the forall a bit further out, to get what you probably want:
data Foo = forall a. Foo a
foo = Foo 1
So that compiles. But what can we do with it? Well, let's try to define an extractor function:
unFoo (Foo x) = x
Oops! Quantified type variable 'a' escapes. So we can define that, but we can't do much interesting with it. If we gave a class context, then we could at least use some of the class functions on it.
There is a time and place for existentials, including ones without class context, but its fairly rare, especially when you're getting started. When you do end up using them, often it will be in the context of GADTs, which are a superset of existential types, but in which the way that existentials arise feels quite natural.
Because the declaration [forall a. a] is (in meaning) the equivalent of saying, "I have a list, and if you (i.e. the computer) pick a type, I guarantee that the elements of said list will be that type."
The compiler is "calling your bluff", so-to-speak, by complaining, "I 'know' that if you give me a 1, that its type is in the Num class, but you said that I could pick any type I wanted to for that list."
Basically, you're trying to use the value of a universal type as if it were the type of a universal value. Those aren't the same thing, though.

Resources