2011-07-09 19 views
16

Tengo una pregunta sobre el polimorfismo de Haskell.¿Cómo maneja Haskell el polimorfismo de sobrecarga?

Como he aprendido, hay dos tipos de polimorfismo:

  1. paramétrico: donde no se especifica el tipo de entrada.

    Ejemplo:

    functionName :: [a] -> a 
    
  2. Sobrecarga: programación como imperativo, es decir, que pasa a diferentes argumentos para la misma función.

Mi problema es: ¿cómo manejar la sobrecarga de Haskell ?

Respuesta

40

La sobrecarga en Haskell se realiza utilizando clases de tipo. Por ejemplo, digamos que usted quiere sobrecargar una función que devuelve un fooInt:

class Fooable a where 
    foo :: a -> Int 

instance Fooable Int where 
    foo = id 

instance Fooable Bool where 
    foo _ = 42 

Sin embargo, ellos son más poderosos que los mecanismos de sobrecarga que se encuentran en la mayoría de los idiomas. Por ejemplo, puede sobrecargar el tipo de retorno:

class Barable a where 
    bar :: Int -> a 

instance Barable Int where 
    bar x = x + 3 

instance Barable Bool where 
    bar x = x < 10 

Para más ejemplos, echar un vistazo a la predefined type classes en Haskell.

+1

@Zach: La sobrecarga de hecho se considera una forma de polimorfismo. Ver: [Polimorfismo Ad-hoc] (http://en.wikipedia.org/wiki/Ad-hoc_polymorphism) en Wikipedia. No estoy seguro de a qué se refiere en la segunda parte de su pregunta. ¿Podrías aclararlo por favor? – hammar

+0

Intento usar la 'clase Barable'. suponiendo que tenemos una variable 'x' igual al Entero' 5'. pero 'bar x' no funcionó. y también en caso de trabajo, ¿qué devolverá '8' o' falso'? es un ejemplo ambiguo. – Jaider

+1

@Jaider: el tipo generalmente se deducirá del contexto donde se usa, aunque puede forzarlo con una anotación de tipo. Pruebe 'bar 5 :: Int' o' bar 5 :: Bool'. – hammar

3

Especifique la firma de tipo de su función en la clase de tipo original, luego cree varias instancias de esa función para la que escribió la firma. Por lo tanto, en el ejemplo que ha publicado hammar, puede pensar que es como polimórfico, y el tipo especificado en cada instancia (por ejemplo, Fooable Bool) es del tipo a (en este caso a es un Bool). Por lo tanto, cuando llama a la función foo con un valor Bool, se invoca la instancia de Fooable para un valor Bool.

Por cierto, puede poner múltiples funciones en la clase de tipo, y puede definir funciones en términos de otras funciones también definidas.

p. Ej.

class Eq a where 
    (==), (/=) :: a -> a -> Bool 

    x /= y = not (x == y) 
    x == y = not (x /= y) 

Puede que no sea obvio aquí, pero si se define una instancia de la ecuación, sólo es necesario definir == o/=, no ambos, ya que se definen en términos de la otra.

4

En algunos lenguajes, medios sobrecarga usando el mismo nombre para varias funciones que proporcionan una funcionalidad similar pero diferente, por lo que podría tratar

split :: String -> [String]      -- splits on whitespace 
split :: Char -> String -> [String]    -- splits on the given character 
split :: [Char] -> String -> [String]   -- splits on any of the given characters 
split :: (Char -> Bool) -> String -> [String] -- splits using a function that tells you when 

que le daría el error Duplicate type signature que está recibiendo.

Haskell no hace este tipo de sobrecarga, y un programador Haskell daría a estos diferentes nombres:

words :: String -> [String]      -- splits on whitespace 
splitOn :: Char -> String -> [String]    -- splits on the given character 
splitsOn :: [Char] -> String -> [String]   -- splits on any of the given characters 
splitWith :: (Char -> Bool) -> String -> [String] -- splits using a function that tells you when 

La razón de que Haskell no permite el tipo de sobrecarga que creo que estás preguntando por , es que realmente no te permite hacer nada que no podrías hacer sin él, y permitirlo haría casi imposible hacer tipos más avanzados de sobrecarga. La sobrecarga de Haskell es una herramienta muy poderosa; averigüe sobre las clases de tipos y las clases de constructores para comenzar.

En realidad, ya String = programadores [Char], y Haskell aman la reutilización de código, que serían mucho más propensos a escribir:

words :: String -> [String]    -- splits on whitespace 
splitOn :: Eq a => a -> [a] -> [[a]]  -- splits on the given item 
splitsOn :: Eq a => [a] -> [a] -> [[a]] -- splits on any of the given items 
splitWith :: (a -> Bool) -> [a] -> [[a]] -- splits using a function that tells you when 

Aquí Eq a es un ejemplo de un tipo de sobrecarga Haskell sí permite, en donde splitOn le permitirá dividir cualquier lista, siempre y cuando los elementos se puedan comparar por igualdad (es decir, Haskell le permite definir su propia noción de igualdad). Puede usar esto para dividir una cadena o, por ejemplo, una lista de cadenas, pero no puede dividir una lista de funciones porque no puede verificar dos funciones para ver si son iguales. splitWith es un ejemplo de Haskell que le permite tratar una función como la mayoría de los demás datos: ¡puede pasar una como argumento!

[Nota 1: words es una función estándar, splitWith está en una biblioteca con una typesignature ligeramente diferente.]
[Nota 2: si desea escribir en realidad estas funciones, se hace así:

splitWith isSplitter list = case dropWhile isSplitter list of 
    [] -> [] 
    thisbit -> firstchunk : splitWith isSplitter therest 
    where (firstchunk, therest) = break isSplitter thisbit 

-- words = splitWith isSpace   -- not needed, standard function from the Prelude 
splitOn c = splitWith (== c)   -- notice I passed == in an argument! 
splitsOn chars = splitWith (`elem` chars) 

]

1

Básicamente anulación es bastante diferente en Haskell, aunque se puede hacer algo similar.

I. Use Clases como respuesta seleccionada.

class YesNo a where 
    yesno :: a -> Bool 

Tienes que hacerlo operativo ejemplo, y entonces usted puede utilizar de esta manera:

> yesno $ length [] 
False 
> yesno "haha" 
True 
> yesno "" 
False 
> yesno $ Just 0 
True 
> yesno True 
True 
ghci> yesno EmptyTree 
False 
> yesno [] 
False 
> yesno [0,0,0] 
True 

http://learnyouahaskell.com/making-our-own-types-and-typeclasses

II. Utilice la coincidencia de patrones de constructor de tipos, tales como:

data Shape = Circle Float Float Float | Rectangle Float Float Float Float 
surface :: Shape -> Float 
surface (Circle _ _ r) = pi * r^2 
surface (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1) 

y luego se puede utilizar como esto:

> surface $ Circle 10 20 10 
314.15927 
> surface $ Rectangle 0 0 100 100 
10000.0 

http://learnyouahaskell.com/making-our-own-types-and-typeclasses

III.Tienen la función "oveloaded" en el módulo sepatate, pero se necesita el prefijo el nombre de importación o importación calificados por nombrar

http://learnyouahaskell.com/modules

0

Aquí, usted tiene un ejemplo sencillo que combina

  • ad- polimorfismo hoc (sobrecarga): misma función con diferente comportamiento para diferentes tipos (por medio de clases de tipo Haskell)

  • polimorfismo paramétrico: misma función con el mismo comportamiento para diferentes tipos (mediante una función de tipo parametrizada. En el principio , el tipo no importa, pero usamos clases de tipos para restringir tipos aceptables).

Código:

import Data.Char 

class MyTypeFamily t where 
     f1 :: t -> Int 
     f2 :: t -> Int 

instance MyTypeFamily Int where 
     f1 x = x*x 
     f2 x = x+x 

instance MyTypeFamily Char where 
     f1 x = (ord x) * (ord x) 
     f2 x = (ord x) + (ord x) 

instance MyTypeFamily Bool where 
     f1 x 
      | x = 10 
      | otherwise = 10 
     f2 x 
      | x = 100 
      | otherwise = -100 

-- ............................................................... 
-- using f1, f2 as "overloaded" functions ("ad-hoc polymorphism) 
-- (the algorithm for f1, f2 is chosen depending on their type) 
-- 
-- using fun as polymorphic (parametric polymorphic function) 
-- the algorithm of fun is always the same but it works on 
-- different types 
fun :: (MyTypeFamily t) => t -> Int 
fun x = (f1 x) + (f2 x) 

-- ............................................................... 
-- ............................................................... 
main = do 
     print $ fun 'J' 
     print $ fun True 
     print $ fun False 
     print $ fun (8 :: Int) 
Cuestiones relacionadas