2010-04-28 7 views
6

Así que estoy escribiendo un programa que devuelve un procedimiento para un problema aritmético dado, así que quise ejemplificar un par de funciones para mostrar para que pueda imprimir la misma expresión que evalúo cuando prueba. El problema es que el código dado coincide (-) con la primera línea cuando debería caer al segundo.Coincidencia de patrones extraños con funciones instancias Mostrar

{-# OPTIONS_GHC -XFlexibleInstances #-} 

instance Show (t -> t-> t) where 
show (+) = "plus" 
show (-) = "minus" 

main = print [(+),(-)] 

vuelve

[plus,plus] 

solo estoy cometiendo un mortal pecado funciones de impresión en el primer lugar o hay alguna manera de que pueda conseguirlo para que coincida correctamente?

editar: Me doy cuenta que estoy recibiendo la siguiente advertencia:

Warning: Pattern match(es) are overlapped 
     In the definition of `show': show - = ... 

Todavía no sé por qué se superpone, o cómo detenerlo.

Respuesta

9

Como sepp2k y MtnViewMark dicho, no se puede patrón de coincidencia en el valor de los identificadores, sólo en constructores y, en algunos casos, cheques de igualdad implícitos. Por lo tanto, su instancia vincula cualquier argumento al identificador, en el proceso sombreando la definición externa de (+). Desafortunadamente, esto significa que lo que estás tratando de hacer no funcionará y nunca funcionará.

Una solución típica para lo que quiere lograr es definir un tipo de datos algebraicos de "expresión aritmética", con una instancia de show apropiada. Tenga en cuenta que puede hacer que su tipo de expresión sea una instancia de Num, con literales numéricos envueltos en un constructor "Literal" y operaciones como (+) que devuelven sus argumentos combinados con un constructor para la operación. Aquí es una forma rápida, ejemplo incompleta:

data Expression a = Literal a 
        | Sum (Expression a) (Expression a) 
        | Product (Expression a) (Expression a) 
        deriving (Eq, Ord, Show) 

instance (Num a) => Num (Expression a) where 
    x + y = Sum x y 
    x * y = Product x y 
    fromInteger x = Literal (fromInteger x) 

evaluate (Literal x) = x 
evaluate (Sum x y) = evaluate x + evaluate y 
evaluate (Product x y) = evaluate x * evaluate y 

integer :: Integer 
integer = (1 + 2) * 3 + 4 

expr :: Expression Integer 
expr = (1 + 2) * 3 + 4 

Ponerlo a prueba en GHCi:

> integer 
13 
> evaluate expr 
13 
> expr 
Sum (Product (Sum (Literal 1) (Literal 2)) (Literal 3)) (Literal 4) 
+0

Eso es fantástico, gracias. (Y mucho más elegante que la solución que proporcioné a continuación.) –

+0

@Sean D: También representa una buena ilustración de dónde fallaría su megaprocesador: considere lo que sucedería si se utilizara con un operador en valores 'Expression Integer' . 'Suma 6 2' no es igual a' Literal 8', a pesar de que mi código es una instancia perfectamente razonable de 'Num'. –

6

Se superpone porque trata (+) simplemente como una variable, lo que significa que en el RHS el identificador + se vinculará a la función a la que llamó show on.

No hay manera de que el patrón coincida con las funciones de la manera que desee.

9

Aquí hay una manera de pensar sobre esto. Considere:

answer = 42 
magic = 3 

specialName :: Int -> String 
specialName answer = "the answer to the ultimate question" 
specialName magic = "the magic number" 
specialName x = "just plain ol' " ++ show x 

¿Puede ver por qué esto no funciona? answer en la coincidencia de patrón es una variable, distinta de answer en el ámbito exterior. Así que en lugar, usted tiene que escribir esto como:

answer = 42 
magic = 3 

specialName :: Int -> String 
specialName x | x == answer = "the answer to the ultimate question" 
specialName x | x == magic = "the magic number" 
specialName x = "just plain ol' " ++ show x 

De hecho, esto es precisamente lo que está sucediendo cuando se escribe constantes en un patrón. Es decir:

digitName :: Bool -> String 
digitName 0 = "zero" 
digitName 1 = "one" 
digitName _ = "math is hard" 

se convierte por el compilador para algo equivalente a:

digitName :: Bool -> String 
digitName x | x == 0 = "zero" 
digitName x | x == 1 = "one" 
digitName _ = "math is hard" 

ya que desea que coincida contra la función obligado a (+) en lugar de obligar a nada al símbolo (+), que' d necesidad de escribir el código como:

instance Show (t -> t-> t) where 
show f | f == (+) = "plus" 
show f | f == (-) = "minus" 

embargo, esto requeriría que las funciones fueron comparables para eq calidad. Y ese es un problema indecidible en general.

Puede responder que solo le está pidiendo al sistema en tiempo de ejecución que compare los punteros a las funciones, pero a nivel del lenguaje, el programador Haskell no tiene acceso a los punteros. En otras palabras, no puede manipular referencias a valores en Haskell (*), solo valores en sí mismos. Esta es la pureza de Haskell y gana transparencia referencial.

(*) MVar s y otros objetos en el IO mónada son otro asunto, pero su existencia no invalida el punto.

+0

¡Todo queda claro! Traté de hacer instancias (+) y (-) de Eq también, pero obviamente (ahora) tampoco tiene sentido. Gracias por la gran respuesta. –

1

lo resolvió a mí mismo con un corte de mega.

instance (Num t) => Show (t -> t-> t) where 
show op = 
    case (op 6 2) of 
     8 -> "plus" 
     4 -> "minus" 
     12 -> "times" 
     3 -> "divided" 
Cuestiones relacionadas