Having read the article Scrap your type classes, I re-implemented some of the ideas shown.
While doing that I came across something really strange: The Type Class - Type can be used as a type constraint! My question: Why is that?
My Code:
{-# LANGUAGE Rank2Types #-}
data IFunctor f = IFunctor {
_fmap :: forall a b. (a -> b) -> f a -> f b
}
-- this type checks...
_fmap2 :: IFunctor f => (a -> b) -> f (f a) -> f (f b)
_fmap2 = \inst -> _fmap inst . _fmap inst
In GHCi the following thing happens:
>>> :t _fmap2 :: IFunctor f => (a -> b) -> f (f a) -> f (f b)
_fmap2 :: IFunctor f => (a -> b) -> f (f a) -> f (f b)
:: IFunctor f -> (a -> b) -> f (f a) -> f (f b)
This doesn't work on GHC 7.8.2. It gives the error Expected a constraint, but ‘IFunctor f’ has kind ‘*’.
Older versions of GHC had a bug where they allowed => to be used like -> in certain situations. This is likely because internally type class constraints are passed as arguments in the form of method dictionaries.
Related
I have a lens(')
myLens' :: (Functor f) => (a -> f a) -> (s -> f s)
And I need a function
lensWithoutFunctor' :: ((a -> b) -> (f a -> f b)) -> (a -> f a) -> (s -> f s)
(The particular type I'm interested in is
type PopType x a = x -> Maybe (a, x)
which could be made into a Functor if I wanted)
Is there a better way to do this other than create a Functor-implementing newtype and then doing something involving "ala"?
Data.Constraint.Forall provides some quantification over constraints, however I fail to see how it can be used. Consider the following:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Forall where
import Prelude
import Data.Constraint.Forall
class Monoid (f a) => MonoidalFunctor f a
testfun :: Forall (MonoidalFunctor f) => (a -> f a) -> [a] -> f a
testfun = foldMap
testfun' :: Monoid (f a) => (a -> f a) -> [a] -> f a
testfun' = foldMap
I thought testfun would typecheck because Forall (MetaMonoid f) would work like forall a. Metamonoid f a, implying forall a. Monoid (f a) because of superclass constraint, but it doesn't.
Why does it not work and is there any workaround? I want to avoid having to write a lot of constraints like MyClass (f MyData) for different MyData types in my function where I know that any useful f will have instances for any f MyData anyway.
Use inst
inst :: forall p a. Forall p a :- p a
inst witness that, if you have forall a. p a, then you can set a to whatever you please and get p a out.
An entailment (:-) is
newtype a :- b = Sub (a => Dict b)
data Dict a = a => Dict
so, by pattern-matching on it, you can reveal the instance within it:
testfun :: forall f a. Forall (MonoidalFunctor f) => (a -> f a) -> [a] -> f a
testfun = case inst #(MonoidalFunctor f) #a of Sub Dict -> foldMap
(type applications/signatures necessary) or you can use (\\):
(\\) :: a => (b => r) -> a :- b -> r
testfun = foldMap \\ inst #(MonoidalFunctor f) #a
which reads "given that a is true and a value of r that also needs b to be true, followed by a value that can prove that b is true given a, make an r. If you rearrange a bit
(\\) :: (b => c) -> (a :- b) -> (a => c)
it looks quite a bit like function composition.
The reason for this dance is simply because it's beyond the reach of GHC to infer that Forall c means it can derive c a for any a; after all, that's why constraints exists. So, you have to be a bit more explicit about it.
I have stumbled on this piece of code fold ((,) <$> sum <*> product) with type signature :: (Foldable t, Num a) => t a -> (a, a) and I got completely lost.
I know what it does, but I don't know how. So I tried to break it into little pieces in ghci:
λ: :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
λ: :t (,)
(,) :: a -> b -> (a, b)
λ: :t sum
sum :: (Foldable t, Num a) => t a -> a
Everything is okay, just basic stuff.
λ: :t (,) <$> sum
(,) <$> sum :: (Foldable t, Num a) => t a -> b -> (a, b)
And I am lost again...
I see that there is some magic happening that turns t a -> a into f a but how it is done is mystery to me. (sum is not even instance of Functor!)
I have always thought that f a is some kind of box f that contains a but it looks like the meaning is much deeper.
The functor f in your example is the so-called "reader functor", which is defined like this:
newtype Reader r = Reader (r -> a)
Of course, in Haskell, this is implemented natively for functions, so there is no wrapping or unwrapping at runtime.
The corresponding Functor and Applicative instances look like this:
instance Functor f where
fmap :: (a -> b) -> (r -> a)_-> (r -> b)
fmap f g = \x -> f (g x) -- or: fmap = (.)
instance Applicative f where
pure :: a -> (r -> a) -- or: a -> r -> a
pure x = \y -> x -- or: pure = const
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
frab <*> fra = \r -> frab r (fra r)
In a way, the reader functor is a "box" too, like all the other functors, having a context r which produces a type a.
So let's look at (,) <$> sum:
:t (,) :: a -> b -> (a, b)
:t fmap :: (d -> e) -> (c -> d) -> (c -> e)
:t sum :: Foldable t, Num f => t f -> f
We can now specialize the d type to a ~ f, e to b -> (a, b) and c to t f. Now we get:
:t (<$>) -- spcialized for your case
:: Foldable t, Num f => (a -> (b -> (a, b))) -> (t f -> f) -> (t f -> (b -> (a, b)))
:: Foldable t, Num f => (f -> b -> (f, b)) -> (t f -> f) -> (t f -> b -> (f, b))
Applying the functions:
:t (,) <$> sum
:: Foldable t, Num f => (t f -> b -> (f, b))
Which is exactly what ghc says.
The short answer is that f ~ (->) (t a). To see why, just rearrange the type signature for sum slightly, using -> as a prefix operator instead of an infix operator.
sum :: (Foldable t, Num a) => (->) (t a) a
~~~~~~~~~~
f
In general, (->) r is a functor for any argument type r.
instance Functor ((->) r) where
fmap = (.)
It's easy to show that (.) is the only possible implementation for fmap here by plugging ((->) r) into the type of fmap for f:
fmap :: (a -> b) -> f a -> f b
:: (a -> b) -> ((->) r) a -> ((->) r) b
:: (a -> b) -> (r -> a) -> (r -> b)
This is the type signature for composition, and composition is the unique function that has this type signature.
Since Data.Functor defines <$> as an infix version of fmap, we have
(,) <$> sum == fmap (,) sum
== (.) (,) sum
From here, it is a relatively simple, though tedious, job of confirming that the resulting type is, indeed, (Foldable t, Num a) => t a -> b -> (a, b). We have
(b' -> c') -> (a' -> b') -> (a' -> c') -- composition
b' -> c' ~ a -> b -> (a,b) -- first argument (,)
a' -> b' ~ t n -> n -- second argument sum
----------------------------------------------------------------
a' ~ t n
b' ~ a ~ n
c' ~ a -> b -> (a,b)
----------------------------------------------------------------
a' -> c' ~ t a -> b -> (a,b)
We can have a polymorphic function f :: a -> b implemented for different pairs of a and b. How can we make
twice :: (a -> b) -> a -> c
twice f x = f (f x)
type check? i.e. how can I write a function which applies a polymorphic function twice?
With Rank2Types we can get a bit closer but not quite there:
{-# LANGUAGE Rank2Types #-}
twice1 :: (forall a. a -> (m a)) -> b -> (m (m b))
twice1 f = f . f
twice2 :: (forall a. m a -> a) -> m (m b) -> b
twice2 f = f . f
so then some polymorphic functions can be applied twice:
\> twice1 (:[]) 1
[[1]]
\> twice2 head [[1]]
1
Can we go further?
The question was asked over Haskell cafe 10 years ago but wasn't quite answered (with type classes it becomes a lot of boilerplate).
{-# LANGUAGE TypeFamilies, RankNTypes, UnicodeSyntax #-}
type family Fundep a :: *
type instance Fundep Bool = Int
type instance Fundep Int = String
...
twice :: ∀ a . (∀ c . c -> Fundep c) -> a -> Fundep (Fundep a)
twice f = f . f
Now, that won't be much use actually because you can't define a (meaningful) polymorphic function that works with any c. One possibility is to toss in a class constraint, like
class Showy a where
type Fundep a :: *
showish :: a -> Fundep a
instance Showy Bool where
type Fundep Bool = Int
showish = fromEnum
instance Showy Int where
type Fundep Int = String
showish = show
twice :: ∀ a b . (Showy a, b ~ Fundep a, Showy b) =>
(∀ c . Showy c => c -> Fundep c) -> a -> Fundep b
twice f = f . f
main = print $ twice showish False
You can't make twice generic enough even in a dependently typed setting, but it's possible with intersection types:
twice :: (a -> b /\ b -> c) -> a -> c
twice f x = f (f x)
Now whenever f :: a -> b and f :: b -> c typecheck, twice will typecheck too.
There is also a beautiful spell in Benjamin Pierce's thesis (I changed the syntax slightly):
self : (A /\ A -> B) -> B
self f = f f
So self-application is typeable with intersection types as well.
I have a type (call it A) and I want to make a typeclass of the functions of type A -> A, A -> A -> A, A -> A -> A -> ... etc. This doesn't work:
{-# LANGUAGE FlexibleInstances #-}
data A = A
class AsToA a where
takeA :: AsToA b => a -> A -> Either A b
instance AsToA (A -> A) where
takeA f a = Left (f a)
instance AsToA b => AsToA (A -> b) where
takeA f a = Right (f a)
I get the following error message:
AsToA.hs:12:22:
Couldn't match expected type ‘b1’ with actual type ‘b’
‘b’ is a rigid type variable bound by
the instance declaration at AsToA.hs:11:10
‘b1’ is a rigid type variable bound by
the type signature for
takeA :: AsToA b1 => (A -> b) -> A -> Either A b1
at AsToA.hs:12:3
Relevant bindings include
f :: A -> b (bound at AsToA.hs:12:9)
takeA :: (A -> b) -> A -> Either A b1 (bound at AsToA.hs:12:3)
In the first argument of ‘Right’, namely ‘(f a)’
In the expression: Right (f a)
Any ideas? Thanks very much for any advice.
There is some confusion between the two bs:
class AsToA a where
takeA :: AsToA b => a -> A -> Either A b
instance AsToA b => AsToA (A -> b) where
takeA f a = Right (f a)
These are not the same. Let's rename the first one to c
class AsToA a where
takeA :: AsToA c => a -> A -> Either A c
instance AsToA b => AsToA (A -> b) where
takeA f a = Right (f a)
Now, Right (f a) has type Either A b but should have type Either A c for any c such that AsToA c holds. This does not type check.
The issue here is that the signature
takeA :: AsToA c => a -> A -> Either A c
promises that takeA can return Either A c for any c, caller's choice. This is not what you want, I guess.
I'm still not sure about what the actual intended result is, but I guess the problem is similar to the following one.
Given a function f of type A->A->...->A return a function
\x -> f x x ..., with one application of
x for each -> in the type (hence of type A->A).
A possible solution is
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
data A = A -- could be anything
class C f where
takeA :: f -> A -> A
instance C (A -> A) where
takeA f = f
instance C b => C (A -> b) where
takeA f = \x -> takeA (f x) x
Note that this requires OverlappingInstances to be used, which is quite evil. I'd recommend to avoid it.
To avoid it, in this case it's enough to define an instance even for the
type A.
{-# LANGUAGE FlexibleInstances #-}
data A = A -- could be anything
class C f where
takeA :: f -> A -> A
instance C A where
takeA a = \_ -> a
instance C b => C (A -> b) where
takeA f = \x -> takeA (f x) x
As mentioned in the comments to the other answer, you might not really need the Either, and takeA is then basically always id, just with a type restriction. If so you can make this a method-less class:
{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}
data A = A
class AsToA a
takeA :: AsToA a => a -> a
takeA = id
instance AsToA (A -> A)
instance AsToA (A -> b) => AsToA (A -> (A -> b))
Alternatively, you might want to convert the functions to a common type that allows you to pass in As dynamically. If so Either won't be enough, but you can define your own:
{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}
data A = A
data R = Result A | MoreArgs (A -> R)
class AsToA a where
takeA :: a -> A -> R
instance AsToA (A -> A) where
takeA f a = Result (f a)
instance AsToA (A -> b) => AsToA (A -> (A -> b)) where
takeA f a = MoreArgs (takeA $ f a)