2012-09-14 3 views
3

Une courte recherche ne m'a pas aidé à trouver la réponse, j'ai donc commencé à douter de son existence. Le simple quêtes: Je veux créer une fonction polymorphique, quelque chose comme ceci:Création de fonctions polymorphes dans Haskell

f :: String -> String 
f s = show (length s) 

f :: Int -> String 
f i = show i 

Une fonction définie différemment pour différents types est destiné. Est-ce possible et comment?

+2

Votre premier 'f' n'a pas le bon type. –

+0

Voir aussi http://stackoverflow.com/questions/5671303/what-is-haskells-style-of-polymorphism –

+0

@DonStewart: merci, c'est une faute de frappe. – aplavin

Répondre

13

Il existe deux types de polymorphisme dans Haskell:

  • polymorphisme paramétrique; et
  • borné polymorphisme

Le premier est le plus général - une fonction paramétrique est polymorphe si elle se comporte de manière uniforme pour tous les types, dans au moins un de ses paramètres de type.

Par exemple, la fonction length est polymorphe: elle renvoie la longueur d'une liste, quel que soit le type enregistré dans sa liste.

length :: [a] -> Int 

Le polymorphisme est indiqué par une variable de type minuscule. Maintenant, si vous avez un comportement personnalisé que vous voulez avoir pour définir de types, alors vous avez un polymorphisme borné (également connu sous le nom "ad hoc"). Dans Haskell, nous utilisons des classes de types pour cela.

La classe déclare que la fonction sera disponible dans un ensemble de types:

class FunnyShow a where 
    funnyshow :: a -> String 

et vous pouvez définir des instances pour chaque type que vous aimez:

instance FunnyShow Int where 
    funnyshow i = show (i+1) 

et peut-être:

instance FunnyShow [Char] where 
    funnyshow s = show (show s) 
+0

Et le 'funnyshow' est-il juste une fonction régulière, ou a-t-il des choses spécifiques à avoir en tête en l'utilisant? – aplavin

+1

C'est une fonction régulière. Vous aurez une erreur de compilation si vous essayez de l'utiliser sur un type pour lequel vous n'avez pas d'instance. –

+0

Merci, cela semble vraiment être la bonne solution.Cependant, il est étrange que je n'ai pas remarqué l'utilisation de 'instance' dans plusieurs programmes de haskell que j'ai examinés. – aplavin

6

Voici comment vous pouvez réaliser quelque chose de similaire en utilisant des familles de types. Eh bien, si vous avez le même type de retour, vous pouvez obtenir le comportement sans utiliser les familles de types et en utilisant uniquement les classes de type comme suggéré par Don.

Mais il est préférable d'utiliser des familles de types lorsque vous souhaitez prendre en charge un polymorphisme adhoc plus complexe, comme différents types de retour pour chaque instance.

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE TypeSynonymInstances #-} 
{-# LANGUAGE TypeFamilies #-} 

class F a where 
    type Out a :: * 
    f :: a -> Out a 

instance F String where 
    type Out String = String 
    f = show . length 

instance F Int where 
    type Out Int = String 
    f = show 

instance F Float where 
    type Out Float = Float 
    f = id 

Dans ghci

*Main> f (2::Int) 
"2" 

*Main> f "Hello" 
"5" 

*Main> f (2::Float) 
2.0 
+2

Les familles type sont belles. –

+0

Comment 'longueur' peut-il retourner un' String'? :) – is7s

+0

@ is7s Désolé, je n'ai pas changé complètement après que l'auteur a modifié la question .. Merci .. corrigé .. – Satvik

Questions connexes