Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the most general typeclass function types

Tags:

haskell

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?

like image 661
Daniel Buckmaster Avatar asked Jun 13 '13 23:06

Daniel Buckmaster


People also ask

What are function types in Haskell?

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.

What is it called when the type of a function contains one or more class constraints?

Overloaded Functions. A polymorphic function is called overloaded if its type contains one or more class constraints.

What are Typeclasses used for?

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.

What are type classes in Haskell?

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.


1 Answers

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
like image 51
leftaroundabout Avatar answered Sep 22 '22 16:09

leftaroundabout