Haskell Typeclass Instance based on canonical view - haskell

As a self assigned exercise of sorts, I'm playing around with implementing an algebra based numeric type heirarchy.
I'd like to specify that if a structure can be viewed in a canonical way as something that satisfies one of my typeclasses, then it should be an instance of that typeclass as well. To that end I've tried essentially the following:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies,
FlexibleContexts, FlexibleInstances #-}
class AbGp s a where
plus :: a -> a -> s -> a
zero :: s -> a
minus :: a -> a -> s -> a
class View a b c | a c -> b
view :: a -> b
instance (View s s1 a, AbGp s1 a) => AbGp s a
plus x y s = plus x y (view s)
zero = zero . view
minus x y s = minus x y (view s)
s should be thought of as holding the definitions of the operations in the group, and a as the type of the elements in the group.
But this doesn't work, which isn't surprising, but what I want to do now is:
Suppose I know that some type s, say s that represents a Ring, can be mapped canonically to s1 which is a datastructure I already have an instance for as an AbGp, then I would like s to also be automatically an instance of AbGp. How can I do this?
I'm thinking of doing the following, if it'll work, but I'd like to know if there is a better way:
instance (AbGp s1 a) => AbGp (s1,b) a where
-- ...

Related

How to change the behavior of the function based on class constraints in Haskell?

I have a data type that represents a collection of values paired with a probability. At first, the implementation was just to use good old lists, but as you can imagine, this can be inefficient (for example, I use a Tree instead of a list to store ordered values)
After some research, I thought about using GADTs
data Tree a b = Leaf | Node {left::Tree a b, val :: (a, b), right :: Tree a b}
data Prob a where
POrd ::Ord a => Tree a Rational -> Prob a
PEq ::Eq a => [(a, Rational)] -> Prob a
PPlain ::[(a, Rational)] -> Prob a
So far, so good. I'm now stuck at trying to create a smart constructor for my new data type,
that takes [(a,Rational)] and depending on the constraints of a, chooses the correct constructor for Prob. Basically:
prob :: [(a, Rational)] -> Prob a
-- chooses the "best" constructor based on the constraints of a
Is this at all possible? If not, how should I go about designing something better? Am I missing something?
Thanks!
There is no way to perform a check of the form "is type T in class C?" in Haskell. The issue here is that it is hard to answer negatively to such question and allow separate compilation: T could be in C in the scope of one module but not in the scope of another one, causing a rather fragile semantics.
To ensure consistency, Haskell only allows to require a constraint, and raise an compile time error otherwise.
As far as I can see, the best you can do is to use another custom type class, which tells you which case is the best one. E.g.
{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, ScopedTypeVariables #-}
data BestConstraint a where
BCOrd :: Ord a => BestConstraint a
BCEq :: Eq a => BestConstraint a
BCNone :: BestConstraint a
class BC a where
bestC :: BestConstraint a
instance BC Int where bestC = BCOrd
-- ... etc.
instance BC a => BC [a] where
bestC = case bestC #a of
BCOrd -> BCOrd
BCEq -> BCEq
BCNone -> BCNone
prob :: forall a . BestConstraint a => [(a, Rational)] -> Prob a
prob xs = case bestC #a of
BCOrd -> POrd .... -- build the tree
BCEq -> PEq xs
BCNone -> PPlain xs
You will have to provide an instance for any type you want to use, though.

Nested Type-Level Programming

I'm attempting to use DataKinds to do type-level programming, but am running into difficulties when I have one of these structures nested in another.
{-# LANGUAGE DataKinds, TypeFamilies, GADTs, MultiParamTypeClasses, FlexibleInstances #-}
module Temp where
data Prop1 = D | E
data Lower :: Prop1 -> * where
SubThing1 :: Lower D
SubThing2 :: Lower E
class ClassLower a where
somefunc2 :: a -> String
instance ClassLower (Lower D) where
somefunc2 a = "string3"
instance ClassLower (Lower E) where
somefunc2 a = "string4"
data Prop2 = A | B | C
data Upper :: Prop2 -> * where
Thing1 :: Upper A
Thing2 :: Upper B
Thing3 :: Lower a -> Upper C
class ClassUpper a where
somefunc :: a -> String
instance ClassUpper (Upper A) where
somefunc a = "string1"
instance ClassUpper (Upper B) where
somefunc a = "string2"
instance ClassUpper (Upper C) where
somefunc (Thing3 x) = somefunc2 x
As soon as I add that last instance of ClassUpper, I end up with an error.
Temp.hs:37:25: error:
• Could not deduce (ClassLower (Lower a))
arising from a use of ‘somefunc2’
from the context: 'C ~ 'C
bound by a pattern with constructor:
Thing3 :: forall (a :: Prop1). Lower a -> Upper 'C,
in an equation for ‘somefunc’
at /Users/jdouglas/jeff/emulator/src/Temp.hs:37:13-20
• In the expression: somefunc2 x
In an equation for ‘somefunc’: somefunc (Thing3 x) = somefunc2 x
In the instance declaration for ‘ClassUpper (Upper 'C)’
I understand that 'C ~ 'C indicates type equality, but I don't understand what the underlying problem is, much less the solution or workaround.
What am I not understanding, and what is the best way to tackle this problem?
The problem here is a bit subtle. The reason one might expect GHC to accept this is that you have instances for all possible Lower a since you only provide ways of making Lower D and Lower E. However, one could construct a pathological definition for Lower like
import GHC.Exts (Any)
data Lower :: Prop1 -> * where
SubThing1 :: Lower D
SubThing2 :: Lower E
SubThing3 :: Lower Any
The point is that not only D and E have kind Prop1. It isn't just with things like Any that we can play such shenanigans - even the following constructor is allowed (so F Int :: Prop1 too)!
SubThing4 :: Lower (F Int)
type family F x :: Prop1 where {}
So, in summary, the underlying problem is that GHC really can't be sure that the ClassLower (Lower a) constraint (needed due to the use of somefunc2) is going to be satisfied. To do so, it would have to do a fair bit of work checking the GADT constructors and making sure that every possible case is covered by some instance.
In this case, you could solve your problem by adding the ClassLower (Lower a) constraint to the GADT constructor (an enabling FlexibleContexts).
data Upper :: Prop2 -> * where
Thing1 :: Upper A
Thing2 :: Upper B
Thing3 :: ClassLower (Lower a) => Lower a -> Upper C
Or you could write out your ClassLower instance like this, using pattern matching (rather than the type variable) to distinguish the cases of the GADT:
instance ClassLower (Lower a) where
somefunc2 SubThing1 = "string3"
somefunc2 SubThing2 = "string4"

Functions with higher kinds?

Suppose the following data types are defined:
data X a = X {getX :: a}
data Y a = Y {getY :: a}
data Z a = Z {getZ :: a}
Must there be three separate functions, getX, getY, and getZ? It seems to me that there could be a function defined something like this:
get :: forall (τ :: (* -> *)) (a :: *). τ a -> a
get (_ x) = x
Obviously this is not valid standard Haskell, but there are so many extensions to GHC that seem like they might have a solution (RankNTypes,ExistentialQuantification,DataKinds,etc.). Besides the simple reason of avoiding a tiny amount of typing, there is the benefit of avoiding the namespace pollution that the record solution creates. I suppose this is really just a more implicit solution than using a type class like this:
class Get f where
get :: f a -> a
However, it appears that defining a generic function would be more useful than a type class, because the fact that it is implicitly defined means it could be used in many more places, in the same way that ($) or (.) is used. So my question has three parts: is there a way to accomplish this, is it a good idea, and if not, what is a better way?
How about this type?
newtype Pred a = Pred (a -> Bool)
Or this one?
data Proxy a = Proxy
There's no way to get an a out of a Pred a. You can only put as in. Likewise, there's no way to get an a out of a Proxy a, because there aren't any as inside it.
So a function get :: forall f a. f a -> a can't exist in general. You need to use a type class to distinguish between those types f from which you can extract an a and those from which you can't.
Well, that unconstrained generic type of get certainly can't work. This would also allow you to extract, say, a Void value from Const () :: Const () Void.
You can however obtain a suitably constrained version of this function quite simply with generics. You still need a type class, but not need to define instances in the traditional sense. It ultimately looks like this:
{-# LANGUAGE TypeFamilies, DeriveGeneric, DeriveAnyClass #-}
import GHC.Generics
class Get τ where
get :: τ a -> a
data X a = X a deriving (Generic1, Get)
data Y a = Y a deriving (Generic1, Get)
data Z a = Z a deriving (Generic1, Get)
To actually get this to work, we only need two weird representation-type instances:
instance Get f => Get (M1 i t f) where get = get . unM1
instance Get Par1 where get = unPar1
Now the actual implementation for X, Y and Z can just use a default signature and reduce the extraction to the underlying type-representation. To this end, define the class thus:
{-# LANGUAGE DefaultSignatures #-}
class Get τ where
get :: τ a -> a
default get :: (Generic1 τ, Get (Rep1 τ)) => τ a -> a
get = get . from1

What can type families do that multi param type classes and functional dependencies cannot

I have played around with TypeFamilies, FunctionalDependencies, and MultiParamTypeClasses. And it seems to me as though TypeFamilies doesn't add any concrete functionality over the other two. (But not vice versa). But I know type families are pretty well liked so I feel like I am missing something:
"open" relation between types, such as a conversion function, which does not seem possible with TypeFamilies. Done with MultiParamTypeClasses:
class Convert a b where
convert :: a -> b
instance Convert Foo Bar where
convert = foo2Bar
instance Convert Foo Baz where
convert = foo2Baz
instance Convert Bar Baz where
convert = bar2Baz
Surjective relation between types, such as a sort of type safe pseudo-duck typing mechanism, that would normally be done with a standard type family. Done with MultiParamTypeClasses and FunctionalDependencies:
class HasLength a b | a -> b where
getLength :: a -> b
instance HasLength [a] Int where
getLength = length
instance HasLength (Set a) Int where
getLength = S.size
instance HasLength Event DateDiff where
getLength = dateDiff (start event) (end event)
Bijective relation between types, such as for an unboxed container, which could be done through TypeFamilies with a data family, although then you have to declare a new data type for every contained type, such as with a newtype. Either that or with an injective type family, which I think is not available prior to GHC 8. Done with MultiParamTypeClasses and FunctionalDependencies:
class Unboxed a b | a -> b, b -> a where
toList :: a -> [b]
fromList :: [b] -> a
instance Unboxed FooVector Foo where
toList = fooVector2List
fromList = list2FooVector
instance Unboxed BarVector Bar where
toList = barVector2List
fromList = list2BarVector
And lastly a surjective relations between two types and a third type, such as python2 or java style division function, which can be done with TypeFamilies by also using MultiParamTypeClasses. Done with MultiParamTypeClasses and FunctionalDependencies:
class Divide a b c | a b -> c where
divide :: a -> b -> c
instance Divide Int Int Int where
divide = div
instance Divide Int Double Double where
divide = (/) . fromIntegral
instance Divide Double Int Double where
divide = (. fromIntegral) . (/)
instance Divide Double Double Double where
divide = (/)
One other thing I should also add is that it seems like FunctionalDependencies and MultiParamTypeClasses are also quite a bit more concise (for the examples above anyway) as you only have to write the type once, and you don't have to come up with a dummy type name which you then have to type for every instance like you do with TypeFamilies:
instance FooBar LongTypeName LongerTypeName where
FooBarResult LongTypeName LongerTypeName = LongestTypeName
fooBar = someFunction
vs:
instance FooBar LongTypeName LongerTypeName LongestTypeName where
fooBar = someFunction
So unless I am convinced otherwise it really seems like I should just not bother with TypeFamilies and use solely FunctionalDependencies and MultiParamTypeClasses. Because as far as I can tell it will make my code more concise, more consistent (one less extension to care about), and will also give me more flexibility such as with open type relationships or bijective relations (potentially the latter is solver by GHC 8).
Here's an example of where TypeFamilies really shines compared to MultiParamClasses with FunctionalDependencies. In fact, I challenge you to come up with an equivalent MultiParamClasses solution, even one that uses FlexibleInstances, OverlappingInstance, etc.
Consider the problem of type level substitution (I ran across a specific variant of this in Quipper in QData.hs). Essentially what you want to do is recursively substitute one type for another. For example, I want to be able to
substitute Int for Bool in Either [Int] String and get Either [Bool] String,
substitute [Int] for Bool in Either [Int] String and get Either Bool String,
substitute [Int] for [Bool] in Either [Int] String and get Either [Bool] String.
All in all, I want the usual notion of type level substitution. With a closed type family, I can do this for any types (albeit I need an extra line for each higher-kinded type constructor - I stopped at * -> * -> * -> * -> *).
{-# LANGUAGE TypeFamilies #-}
-- Subsitute type `x` for type `y` in type `a`
type family Substitute x y a where
Substitute x y x = y
Substitute x y (k a b c d) = k (Substitute x y a) (Substitute x y b) (Substitute x y c) (Substitute x y d)
Substitute x y (k a b c) = k (Substitute x y a) (Substitute x y b) (Substitute x y c)
Substitute x y (k a b) = k (Substitute x y a) (Substitute x y b)
Substitute x y (k a) = k (Substitute x y a)
Substitute x y a = a
And trying at ghci I get the desired output:
> :t undefined :: Substitute Int Bool (Either [Int] String)
undefined :: Either [Bool] [Char]
> :t undefined :: Substitute [Int] Bool (Either [Int] String)
undefined :: Either Bool [Char]
> :t undefined :: Substitute [Int] [Bool] (Either [Int] String)
undefined :: Either [Bool] [Char]
With that said, maybe you should be asking yourself why am I using MultiParamClasses and not TypeFamilies. Of the examples you gave above, all except Convert translate to type families (albeit you will need an extra line per instance for the type declaration).
Then again, for Convert, I am not convinced it is a good idea to define such a thing. The natural extension to Convert would be instances such as
instance (Convert a b, Convert b c) => Convert a c where
convert = convert . convert
instance Convert a a where
convert = id
which are as unresolvable for GHC as they are elegant to write...
To be clear, I am not saying there are no uses of MultiParamClasses, just that when possible you should be using TypeFamilies - they let you think about type-level functions instead of just relations.
This old HaskellWiki page does an OK job of comparing the two.
EDIT
Some more contrasting and history I stumbled upon from augustss blog
Type families grew out of the need to have type classes with
associated types. The latter is not strictly necessary since it can be
emulated with multi-parameter type classes, but it gives a much nicer
notation in many cases. The same is true for type families; they can
also be emulated by multi-parameter type classes. But MPTC gives a
very logic programming style of doing type computation; whereas type
families (which are just type functions that can pattern match on the
arguments) is like functional programming.
Using closed type families
adds some extra strength that cannot be achieved by type classes. To
get the same power from type classes we would need to add closed type
classes. Which would be quite useful; this is what instance chains
gives you.
Functional dependencies only affect the process of constraint solving, while type families introduced the notion of non-syntactic type equality, represented in GHC's intermediate form by coercions. This means type families interact better with GADTs. See this question for the canonical example of how functional dependencies fail here.

Simpler syntax for overloading function names

In Haskell with the type families extension, this is perfectly legal (ideone):
{-# LANGUAGE TypeFamilies #-}
type family F a
data A = A Int
data B = B Double
type instance F A = Int
type instance F B = Double
class Get a where
get :: a -> F a
instance Get A where
get (A x) = x
instance Get B where
get (B x) = x
main = print $ (get (A 3), get (B 2.0))
Basically I've defined two functions get.
One with type signature:
get :: A -> Int
And the second:
get :: B -> Double
However, there's a lot of cruft in the code above. What I'd like to be able to do is this:
get :: A -> Int
get (A x) = x
get :: B -> Double
get (B x) = x
I understand using this syntax exactly won't work, but is there any way I can get what I want to achieve without a dozen lines defining type instances and class instances? Considering first code works fine, I see no reason why the Haskell compiler can't this shorter code into the above anyway.
This should do the job:
class Get a b | a -> b where
get :: a -> b
instance Get A Int where
...
https://www.haskell.org/haskellwiki/Functional_dependencies
Okay, so it only got rid of type families. I don't think you can get rid of type classes, as they are the method of implementing overloading. Besides, without a class, you would not be able to express class constraints in types, e.g. you could not write this:
getPaired :: (Get a b, Get c d) => (a, c) -> (b, d)
I don't know if this is applicable to your use case - your example is rather contrived. But you can use a GADT instead of type classes here:
data T a where
A :: Int -> T Int
B :: Double -> T Double
get :: T a -> a
get (A x) = x
get (B x) = x
In general, there is no way to get the compiler to guess what code you want to write and write it for you. Such a compiler would obsolete a majority of programmers, I suspect, so we should all be glad it doesn't exist. I do agree that you are writing quite a lot to do very little, but perhaps that is a sign there is something wrong with your code, rather than a deficit in the compiler.
Here is another alternative:
{-# LANGUAGE TypeFamilies #-}
data A = A Int
data B = B Double
class Get a where
type F a
get :: a -> F a
instance Get A where
type F A = Int
get (A x) = x
instance Get B where
type F B = Double
get (B x) = x
main = print (get (A 3), get (B 2.0))
It looks nicer to me, than functional dependencies.
All the stuff is described at https://www.haskell.org/haskellwiki/GHC/Type_families

Resources