"class TypeClassName a b where" is incorrect syntax? - haskell

I am learning Haskell and I am not quite sure whether class TypeClassName a b where is incorrect.
Does it make sense to write something like that in Haskell?
I know that class TypeClassName a where is correct but I am not sure whether the extra b would make any sense there ?

You can do that with Multi-parameter type class extension enabled.
{-# LANGUAGE MultiParamTypeClasses #-}
Regarding it's usage and requirement, it actually depends upon your application. For example, in the linked tutorial for type family they actually have to use this extension. Also, this wikibook section explains how it is used for Collection type class. For Collection typeclass, multi parameter type class makes good use case:
{-# LANGUAGE MultiParamTypeClasses #-}
class Eq e => Collection c e where
insert :: c -> e -> c
member :: c -> e -> Bool
Here c is the collection type like List and e is the element inside the collection. So any collection which supports insert and memebership test function can be made instance of this typeclass.

Related

Haskell subclassing and instance overlap

Coming from the OOP world, I sometimes find myself trying to use the inheritance pattern in Haskell, with varying degrees of success. Here's a little puzzle I encountered with subclassing (using GHC 8.10.7).
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.List (sort)
class Collection c a where
-- gets list of elements in the collection
elements :: c a -> [a]
class OrderedCollection c a where
-- gets sorted list of elements in the collection
orderedElements :: c a -> [a]
instance (Ord a, OrderedCollection c a) => Collection c a where
-- "default" implementation
elements = orderedElements
newtype SortedList a = SortedList [a]
deriving Show
instance (Ord a) => OrderedCollection SortedList a where
-- need to sort the elements in the list
orderedElements (SortedList xs) = sort xs
instance Collection SortedList a where
-- "optimized" implementation: no need to sort
elements (SortedList xs) = xs
test :: (Ord a, Show a, OrderedCollection c a) => c a -> IO ()
test coll = do
putStrLn $ "ordered elements: " ++ show (orderedElements coll)
putStrLn $ "elements: " ++ show (elements coll)
myList :: SortedList Int
myList = SortedList [3, 2, 1]
main :: IO ()
main = do
test myList
After including the necessary language extensions, this still gave me an error: Overlapping instances for Collection c a arising from a use of ‘elements’. It suggests using IncoherentInstances. Since this extension is now deprecated in favor of per-instance pragmas, I added an INCOHERENT pragma to the subclass instance:
instance {-# INCOHERENT #-} (Ord a, OrderedCollection c a) => Collection c a where
...
This successfully compiled. However, the result was not what I expected, as the output was:
ordered elements: [1,2,3]
elements: [1,2,3]
What I wanted was for the specialized implementation of Collection for SortedList to override the default (in an OO language, SortedList would inherit from OrderedCollection and then override the elements method). But here the type checker does not know to use SortedList's custom Collection implementation, because the type signature of test only imposes the constraint OrderedCollection c a.
Next, I tried adding the Collection constraint:
test :: (Ord a, Show a, Collection c a, OrderedCollection c a) => c a -> IO ()
This gave me the output I wanted:
ordered elements: [1,2,3]
elements: [3,2,1]
However, GHC also issued a warning about "fragile inner bindings" and suggested I add the MonoLocalBinds extension, which silences that warning. In any case, I'm not thrilled with having to include the Collection c a constraint (given it's implied by OrderedCollection c a), or having to use incoherent instances.
Interestingly, if I changed the INCOHERENT pragma to OVERLAPPABLE, it still compiled, and it also allowed me to remove MonoLocalBinds.
My question is, are there any alternative approaches to achieving the desired "inheritance" behavior here, without needing the redundant constraint in test?
When you write this:
instance ... => Collection c a where
You're declaring a Collection instance for all types ever. And it doesn't matter at all what's on the left of the fat arrow =>. Constraints do not participate in instance resolution. When the compiler tries to lookup an instance for a particular type, it only looks at what's on the right of the fat arrow =>, and only after finding a matching instance does it check if its constraints are satisfied. And if they're not, the compiler won't go back to look for another instance. That's how instance resolution works, and there are good reasons for it.
So, to reiterate: Collection c a means that this is an instance for all types.
And therefore, any subsequent Collection instances you might declare would of course be overlapping.
Thankfully, in this particular case, there is a better way: you can declare default methods without creating a universal instance like that. To do that, declare the method right inside the class declaration. And yes, you can put constraints on it too (see docs):
class Collection c a where
-- gets list of elements in the collection
elements :: c a -> [a]
default elements :: OrderedCollection c a => c a -> [a]
elements = orderedElements
But more generally, while type classes plus existential quantification is technically equivalent to OOP-style class hierarchies, if you try to actually model your domain like that, it would be more and more awkward and painful the further you go. It's a bit like trying to model ADTs in something like Java. Technically possible, but oh so messy!
There are some legitimate cases where a class hierarchy may make sense (one notable example is the GHC exception system), but most of the time there are much simpler ways.

Typeclass resolution in Haskell reporting ambiguity even if there is only one instance

I am experimenting with transitive typeclass instances in Haskell. It is well-known that one cannot declare a transitive instance in the original typeclass (i.e. (C a b, C b c) => C a c). Therefore I tried to define another class representing the transitive closure of the original class instead. Minimal code is as below:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Ambig where
class Coe a b where
from :: a -> b
class CoeTrans a b where
from' :: a -> b
instance CoeTrans a a where
from' = id
instance (Coe a b, CoeTrans b c) => CoeTrans a c where
from' = from' . from #a #b
instance Coe Bool Int where
from False = 0
from True = 1
instance Coe Int Integer where
from x = toInteger x
where CoeTrans is the transitive closure of Coe. When I'm trying to use from' in CoeTrans, however, it always reports ambiguity:
-- >>> from' True :: Integer
-- Ambiguous type variable ‘b0’ arising from a use of ‘from'’
-- prevents the constraint ‘(Coe Bool b0)’ from being solved.
-- Probable fix: use a type annotation to specify what ‘b0’ should be.
-- These potential instance exist:
-- instance Coe Bool Int
-- -- Defined at /Users/t/Desktop/aqn/src/Ambig.hs:21:10
Even if there is virtually only one instance. But according to GHC docs a typeclass resolution will succeed iff there is one applicable instance.
Why would this happen and is there any way to solve the transitive instance problem?
I think you misunderstood the docs a bit. They really say that a typeclass resolution for a given type will succeed iff one instance is present. But in your case, no type is given. b0 is ambiguous.
The compiler needs to know b0 before it can pick an instance of Coe Bool b0, even though there is only one in the current scope. And this is done this way on purpose. And the key words there are "current scope". You see, if the compiler could just pick whatever is available in scope, your program would be vulnerable to subtle changes in scope: you may change your imports, or some of your imported modules may change their internal structure. This may result in different instances appearing or disappearing in your current scope, which may result in different behaviour of your program without any kind of warning.
If you really intend for there to always be at most one unambiguous path between any two types, you can solve it by adding a functional dependency to Coe:
class Coe a b | a -> b where
from :: a -> b
This will have two effects:
The compiler will know that it can always deduce b just by knowing a.
And to facilitate that, the compiler will prohibit multiple instances with same a, but different bs from being defined.
Now the compiler can see that, since the argument of from' is Bool, it must search for an instance of Coe Bool b for some b, and from there it will know for sure what b has to be, and from there it can search for the next instance, and so on.
If, on the other hand, you really intended for there to be multiple possible paths between two given types, and for the compiler to just pick one - you're out of luck. The compiler refuses on principle` to randomly pick one of multiple possibilities - see explanation above.

how to define a class with a type family [duplicate]

This question already has an answer here:
How to make lenses for records with type-families [duplicate]
(1 answer)
Closed 3 years ago.
The following code generates an "Expected a constraint" error :
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ExistentialQuantification #-}
type family Note a
type instance Note String = String
data SomeNote = forall a. Note a => SomeNote a
class HasNote b where
noteOf :: b -> SomeNote
The error is Expected a constraint, but 'Note a' has kind '*', in the definition of SomeNote. Why ? How can I fix it ?
The goal is to include an instance of the Note type family in some data structure b, and use noteOf b to extract it, whatever the instance is.
The goal is to include an instance of the Note type family in some data structure b, and use noteOf b to extract it
That's not how type families work. All you've really said is that you can map one type, represented by variable a into another type via the type function Note. It doesn't mean values of type a contain a value of type Note b at all. It is the type class that rather strongly implies the Note a type is within or computable from the a type.
The code is along the lines of:
type family Note a
type instance Note String = String
class SomeNote a where
noteOf :: a -> Note a
Even better, consider using an associated type:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
class SomeNote a where
type Note a :: *
noteOf :: a -> Note a
instance SomeNote String where
type Note String = String
noteOf = id

Haskell: type classes: multiple inheritance example

I came to know that we can achieve multiple inheritance using type classes. I had written small haskell code, but unable to figure out the problem.
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE StandaloneDeriving #-}
class (Eq a, Show a) => C a where
getHashCode :: a -> Integer
getHashCode obj = 123
type Id = Int
type Name = String
data Employee = Employee Id Name deriving C
When i tried to load above code, I am getting following error. Any help on this.
No instance for (Eq Employee)
arising from the 'deriving' clause of a data type declaration
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
When deriving the instance for (C Employee)
Failed, modules loaded: none.
I searched google some time, but unable to found good example for multiple inheritance. it will be helpful if you provide some info, example on multiple inheritance in Haskell.
Reference: https://www.haskell.org/tutorial/classes.html
Saying
class (Eq a, Show a) => C a where
does not mean that types that implement C automatically implement Eq and Show, it means that they must first implement Eq and Show before they can implement C.
A class in Haskell is not the same as a class in Java, either, it's closer to an interface, but it can't be used in the same ways (and shouldn't). Haskell doesn't actually have a concept of inheritance or classes in the OOP sense, as it's not an OOP language.
However, if you want to have Eq and Show instances automatically for a type, just add them to the deriving clause of the data type.

Predicate with forall quantifier in haskell?

I want to write the function which accepts values of types, which has instances of multiparameter type class together with every type. Something like this (signature of test function is illegal):
class Test a b
test :: forall a. (forall b. Test a b) => a -> a
Is there a way to express such restriction?
Depending on what you're trying to achieve, there may be a better solution.
But what you're asking is also possible, using the constraints package.
{-# LANGUAGE FlexibleContexts, ConstraintKinds, MultiParamTypeClasses #-}
import Data.Constraint.Forall
class Test a b
test :: Forall (Test a) => a -> a
test = undefined

Resources