I'm trying to write a simple genetic algorithm in Haskell. I figured the first step should be to make a typeclass for individuals that are 'genetic', like so:
class Genetic a where
fitness :: (Ord b) => a -> b
This seems reasonable to me - I don't necessarily want to restrict fitness functions to a type like Float
or Double
, and conceptually all a fitness function should do is provide an ordering of the individuals.
However, when I implement this typeclass for a String
wrapper:
data DNA = DNA String
instance Genetic DNA where
fitness (DNA s) = length s
I see the following error in GHC:
Could not deduce (b ~ Int)
from the context (Ord b)
bound by the type signature for fitness :: Ord b => DNA -> b
Is this not how I should define typeclass functions? Do I have to restrict the function to a specific concrete type, or provide another type variable to the typeclass constructor?
Functions can also be passed as arguments or returned (as we have seen). Their types are given in the type signature. *Main> :t map map :: (a -> b) -> [a] -> [b] *Main> :t filter filter :: (a -> Bool) -> [a] -> [a] flip_args :: (a -> b -> c) -> b -> a -> c flip_args f x y = f y x.
Overloaded Functions. A polymorphic function is called overloaded if its type contains one or more class constraints.
A typeclass is a sort of interface that defines some behavior. If a type is a part of a typeclass, that means that it supports and implements the behavior the typeclass describes. A lot of people coming from OOP get confused by typeclasses because they think they are like classes in object oriented languages.
Type Classes are a language mechanism in Haskell designed to support general overloading in a principled way. They address each of the concerns raised above. They provide concise types to describe overloaded functions, so there is no expo- nential blow-up in the number of versions of an overloaded function.
Luqui explained what the problem is: fitness
would need to be able to provide any Ord
instance the caller might request, when what you really want is some specific one that suits the type best.
This is IMO a very nice application for associated type synonyms:
{-# LANGUAGE TypeFamilies, FlexibleInstances, FlexibleContexts #-}
class (Ord (Fitness a)) => Genetic a where
type Fitness a :: *
fitness :: a -> Fitness a
data DNA = DNA String
instance Genetic DNA where
type Fitness DNA = Int
fitness (DNA s) = length s
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With