Haskell: when to use type class and when to use concrete type? - haskell

When declaring functions, we could either use type class or concrete type(Am I right?) So I can use "Num" as type indicator or "Int". I'm not sure if "Int" has any definition out of "Num"? Can I define my own concrete type that "inherit" from "Num"?
I ask this question from java/C# inheritance perspective, just begin with Haskell. Would you give some hints?

From the OO perspective, a type class is something like an interface or a trait. In Haskell you generally use concrete types when you require a certain structure of the datatype (because you will unpack it), and a type class when you just want a certain behavior. For example, you can write
f :: Int -> Int -> Int
f x y = x + y
but you do not use the internal structure of Ints here; you just need something that supports addition, which is Num (note that it has a (+) in method list):
f :: Num a => a -> a -> a
f x y = x + y
And yes, of course, you can declare that your own class supports the Num interface. Look at the link above, there is a list of methods called "minimal complete definition". This is what other functions that use it will rely on. In a pinch, you may explicitly set some methods to undefined, but you'll get a runtime error if someone tries to call them:
data MyData = MyData Int Int
instance Num MyData where
(MyData x1 y1) + (MyData x2 y2) = MyData (x1 + y1) (x2 + y2)
(*) = undefined
...
See how you use your knowledge of MyData structure to abstract possible users of your class from it? If they want to add two values of this type together, they do not need to know how the data is arranged inside, they just need to know that it is an instance of Num.

Related

Where to put code responsible with value extraction from various functors

Given a functor and given a specific way you want to unwrap its value , is there a predefined typeclass that you should implement to unwrap it?
For example given a type: data X = X Int Int where can i specialize the unwrapping of a Maybe X?
Lets say i have a a = Just (X 2 3) and i want to unwrap it the in a custom way:
(Just 2 3)-> 2^3
Nothing -> 0
But i also want to use the same method/interface to unwrap another type like a Maybe (Int,Int) like:
Just (x, y) -> x + y
Nothing -> 0
The question is more about organisation:
Is there a typeclass method where i can implement for unwrapping a Maybe X,Maybe Y, Either Z, Either K, etc.?
Or do i have to provide ungrouped (not a typeclass method instance) methods for each type that i want to unwrap from the functor?

Using Template Haskell to derive classes

So, I found myself doing something like this:
newtype T x = T x deriving (Eq, Ord, ...)
And I thought this was annoying, so I'm thinking about making a package, using Template Haskell, that adds all the instances in base.
Perhaps it could even be more flexible than just dealing with what's above.
Firstly, it seems like Template Haskell can only spit out declarations, so I think I want to use standalone deriving. In general, I think I want to produce declarations something like this:
deriving instance (F x1, F x2, ... , F xn) => T x1 x2 x3
Where F is replaced by Eq, Ord, etc.
But the right hand side could be a bit more complex, for example:
deriving instance (F x1, F x2, ... , F xn) => T x1 (Maybe x2) x3
Or maybe even
deriving instance (F x1, F x2, ... , F xn) => T x1 (T2 x2 x3)
You could even have repeats:
deriving instance F x => T x x
Lets simplify things for a moment here, and assume there is only one parameter on the left. So we're looking at instances like this:
deriving instance F x => T (some stuff involving x)
I figure what I need is a function like the following:
(Name -> Type) -> Q [Dec]
Then I keep each class in base in a list (i.e. Eq, Ord etc). Then for each class of that list, I create a dummy variable, apply the class to it on the left hand side of the =>, and pass it to the Name -> Type argument passed to get the right hand side of the =>. I can the spit that out as a splice.
I think I can do the Template Haskell for the above function, but the problem is, how does a user use that Template Haskell function?
I think something like \x -> [| UserT x x |] won't work, will it?
I want the user to be able to do something like:
data A t = A t (Maybe t)
deriveClasses (\x -> A x)
How can I make this sort of thing nice for the end user? I hope this question makes some sort of sense, the thing I'm currently most focused on is a form that's easy for the user to use. When it comes to the actual writing of the Template Haskell I think I should be able to handle that.

Does Haskell support anonymous instances of typeclass?

I have the following code in F# (it's from a book)
open System.Collections.Generic
type Table<'T, 'U> =
abstract Item : 'T -> 'U with get
abstract Discard : unit -> unit
let memoizeAndPermitDiscard f =
let lookasideTable = new Dictionary<_, _>(HashIdentity.Structural)
{new Table<'T, 'U> with
member t.Item
with get(n) =
if lookasideTable.ContainsKey(n) then
lookasideTable.[n]
else
let res = f n
lookasideTable.Add(n, res)
res
member t.Discard() =
lookasideTable.Clear()}
let rec fibFast =
memoizeAndPermitDiscard (fun n ->
printfn "computing fibFast %d" n
if n <= 2 then 1 else fibFast.[n - 1] + fibFast.[n - 2])
As we can see the abstract type Table take it's implementation in the function memoizeAndPermitDiscard. Can Haskell do the same?
Apologies in advance: I'm not an F# expert, so I may be misreading the F# code. But if I'm reading it right it's fairly straightforward to translate to Haskell:
data Table t u = Table { get :: t -> IO u, discard :: IO () }
memoize :: Hashable t => (t -> u) -> IO (Table t u)
memoize f = do
tbl <- newHashTable
return Table
{ get = \t -> do
result <- lookupHashTable t tbl
case result of
Nothing -> let u = f t in writeHashTable t u tbl >> return u
Just u -> return u
, discard = clearHashTable tbl
}
I'm assuming some suitable hash table implementation here that offers newHashTable, lookupHashTable, writeHashTable, and clearHashTable. Implementing these (or suggesting a library that offers them) is sort of beside the point of the question, I think.
I'm not an F# expert either, but I believe what you're describing is where you create a anonymous single-use subclass, by declaring in at the point where you create an object how it implements the methods of a superclass or interface? So it's really an anonymous class, not an anonymous instance (or rather, it's no more anonymous than any other object-oriented instance, which typically don't have names inherently, only variable names storing references to them).
It doesn't really make sense to do that with Haskell type classes/instances. The reason is that a Haskell instance represents something very different from an OO instance.
The instances of OO classes are objects (even the instances of interfaces are objects). All of a class' methods will always be invoked on an instance of that class. So it makes sense to create an anonymous subclass of an existing class or interface at the time you create a new object. You basically say how that object implements the required methods, as an alternative to declaring a whole named class of objects that implement the methods the same way, which you could instantiate in multiple places.
The instances of Haskell classes are types (which is why the're called type classes). All of the methods of a class must involve the type somehow, but there is no guarantee that they take an input of the type. For example, consider the class1:
class Monoid' a
where mempty' :: a
mappend' :: a -> a -> a
It doesn't really make sense to say an object is an instance of Monoid'; if I were to create a new object and I wanted to anonymously instantiate Monoid', how would I define mempty'? mempty' isn't an operation I could invoke on my new object, it's an operation that receives no inputs at all (not even an implicit "this") and produces a value2.
And then there's things like:
class Functor' f
where fmap :: (a -> b) -> (f a -> f b)
Nothing ever takes an input of a type f that is an instance of Functor'; it doesn't even make sense to talk about something that might, since the instances of the class Functor' are type constructors that need a type parameter to result in a type, not types that actually contain values. So again, it just makes no sense at the point that I'm creating a new object to say "and here's how this object implements Functor'").
It could potentially make sense to declare a new anonymous type locally, and declare how it implements some type classes at the same time. But Haskell has no syntax for it, no.
Fortunately, you also don't need to create anonymous classes/instances in order to have a one-off collection of functions that conforms to a known interface. Functions are first-class values too, so you can just have type whose fields are functions. Then anywhere you like you can create a new value of that type by providing a definition for all of the function fields. For example:
data MyInterface = MyInterface
{ foo :: Int -> Bool
, bar :: Int -> String
}
example :: MyInterface -> Int -> (Bool, String)
example impl x
= (foo impl x, bar impl x)
main = do
let impl = MyInterface { foo = even, bar = show }
print $ example impl 7
The above program prints (False,"7").
1 I'm using Monoid' rather than Monoid (and similarly Functor') because I'm using simplifications of the real classes. You can see the real definition with :info Monoid in ghci (or look up the documentation) if you're interested.
2 Or alternatively, the class Monoid' mandates that there simply exists a value of each type that instantiates it, and mempty' just is a reference to it.

Haskell Either with fixed types

I have two types, assume they both have monoid implementations. Is there a way to have another type that will be specified to contain an X or a Y? Or is this not the right way to go about this?
data X = X [Int]
data Y = Y Double
The OP has clarified in the comments that they want 'instance behaviour' for some type Either X Y. Typically, you'd use a newtype in this situation:
newtype EitherXY = EitherXY (Either X Y)
In case you're not already aware, newtypes can have a record-like unwrapping function.
newtype EitherXY = EitherXY { unwrap :: Either X Y } deriving (...)
You may also auto-derive certain type classes (as with data declarations). The set of derivable classes depends on the compiler version and the set of enabled extensions. I won't elaborate on it here.
It's probably better to just do
data X_Or_Y = InX X | InY Y
This type is isomorphic to Either X Y, but it's easier to work with/pattern match on than a newtype, since it only has 2 layers of nested constructors

Practical applications of Rank 2 polymorphism?

I'm covering polymorphism and I'm trying to see the practical uses of such a feature.
My basic understanding of Rank 2 is:
type MyType = ∀ a. a -> a
subFunction :: a -> a
subFunction el = el
mainFunction :: MyType -> Int
mainFunction func = func 3
I understand that this is allowing the user to use a polymorphic function (subFunction) inside mainFunction and strictly specify it's output (Int). This seems very similar to GADT's:
data Example a where
ExampleInt :: Int -> Example Int
ExampleBool :: Bool -> Example Bool
1) Given the above, is my understanding of Rank 2 polymorphism correct?
2) What are the general situations where Rank 2 polymorphism can be used, as opposed to GADT's, for example?
If you pass a polymorphic function as and argument to a Rank2-polymorphic function, you're essentially passing not just one function but a whole family of functions – for all possible types that fulfill the constraints.
Typically, those forall quantifiers come with a class constraint. For example, I might wish to do number arithmetic with two different types simultaneously (for comparing precision or whatever).
data FloatCompare = FloatCompare {
singlePrecision :: Float
, doublePrecision :: Double
}
Now I might want to modify those numbers through some maths operation. Something like
modifyFloat :: (Num -> Num) -> FloatCompare -> FloatCompare
But Num is not a type, only a type class. I could of course pass a function that would modify any particular number type, but I couldn't use that to modify both a Float and a Double value, at least not without some ugly (and possibly lossy) converting back and forth.
Solution: Rank-2 polymorphism!
modifyFloat :: (∀ n . Num n => n -> n) -> FloatCompare -> FloatCompare
mofidyFloat f (FloatCompare single double)
= FloatCompare (f single) (f double)
The best single example of how this is useful in practice are probably lenses. A lens is a “smart accessor function” to a field in some larger data structure. It allows you to access fields, update them, gather results... while at the same time composing in a very simple way. How it works: Rank2-polymorphism; every lens is polymorphic, with the different instantiations corresponding to the “getter” / “setter” aspects, respectively.
The go-to example of an application of rank-2 types is runST as Benjamin Hodgson mentioned in the comments. This is a rather good example and there are a variety of examples using the same trick. For example, branding to maintain abstract data type invariants across multiple types, avoiding confusion of differentials in ad, a region-based version of ST.
But I'd actually like to talk about how Haskell programmers are implicitly using rank-2 types all the time. Every type class whose methods have universally quantified types desugars to a dictionary with a field with a rank-2 type. In practice, this is virtually always a higher-kinded type class* like Functor or Monad. I'll use a simplified version of Alternative as an example. The class declaration is:
class Alternative f where
empty :: f a
(<|>) :: f a -> f a -> f a
The dictionary representing this class would be:
data AlternativeDict f = AlternativeDict {
empty :: forall a. f a,
(<|>) :: forall a. f a -> f a -> f a }
Sometimes such an encoding is nice as it allows one to use different "instances" for the same type, perhaps only locally. For example, Maybe has two obvious instances of Alternative depending on whether Just a <|> Just b is Just a or Just b. Languages without type classes, such as Scala, do indeed use this encoding.
To connect to leftaroundabout's reference to lenses, you can view the hierarchy there as a hierarchy of type classes and the lens combinators as simply tools for explicitly building the relevant type class dictionaries. Of course, the reason it isn't actually a hierarchy of type classes is that we usually will have multiple "instances" for the same type. E.g. _head and _head . _tail are both "instances" of Traversal' s a.
* A higher-kinded type class doesn't necessarily lead to this, and it can happen for a type class of kind *. For example:
-- Higher-kinded but doesn't require universal quantification.
class Sum c where
sum :: c Int -> Int
-- Not higher-kinded but does require universal quantification.
class Length l where
length :: [a] -> l
If you are using modules in Haskell, you are already using Rank-2 types. Theoretically speaking, modules are records with rank-2 type properties.
For example, the Foo module below in Haskell ...
module Foo(id) where
id :: forall a. a -> a
id x = x
import qualified Foo
main = do
putStrLn (Foo.id "hello")
return ()
... can actually be thought as a record as follows:
type FooType = FooType {
id :: forall a. a -> a
}
Foo :: FooType
Foo = Foo {
id = \x -> x
}
P/S (unrelated this question): from a language design perspective, if you are going to support module system, then you might as well support higher-rank types (i.e. allow arbitrary quantification of type variables on any level) to reduce duplication of efforts (i.e. type checking a module should be almost the same as type checking a record with higher rank types).

Resources