2010-04-18 17 views
6

Quiero anular los constructores de enteros predeterminados en Haskell para que produzcan cadenas (principalmente por curiosidad, pero temporalmente para hacer una buena alternativa de entrada para el inconveniente de LaTeX \ frac {} {}).¿Cómo se puede omitir para un nuevo tipo?

que quería ser capaz de utilizar el lenguaje en sí mismo, en vez de un programa de análisis especial, pero supongo que probablemente no va a funcionar ...

module Main where 

import Prelude hiding ((+)) 

newtype A = A Int deriving (Eq, Show, Num) 
default (A) 

(+) :: A -> (A -> String) 
(A a) + (A b) = (show a) ++ " + " ++ (show b) 

main2 = 3+4 

main :: IO() 
main = putStrLn main2 

El problema con lo anterior es que el + la función solo funciona para (A, A) en lugar de (A, String), etc. Si uno simplemente deja de lado la coincidencia de patrón "(A a)" y escribe "a", la función show() antepone "A" entonces "3" se convierte en "A 3" en lugar de solo "3".

Quiero anular Mostrar para A, pero parece ser un dolor de cabeza ...

Respuesta

14

si desea que su propia instancia para ShowA, entonces simplemente no lo hacen derivarla y hacer su propia instancia:

newtype A = A Int deriving (Eq, Num) 

instance Show A where 
    show (A a) = show a 

entonces usted puede escribir algo como:

(+) :: (Show a, Show b) => a -> b -> String 
a + b = show a ++ " + " ++ show b 

Por supuesto, si usted está definiendo su propio operador + así, entonces no creo que su problema requiere la declaración newtype A:

module Main where 

import Prelude hiding ((+)) 

(+) :: (Show a, Show b) => a -> b -> String 
a + b = show a ++ " + " ++ show b 

aSum = 3 + 4 

main :: IO() 
main = putStrLn aSum 
+0

Gracias, pero no es muy compositivo: 3 + 4 + 2 rinde '' 3 + 4 '' + 2 '. Perdón por ser un novato ... si conoce una forma de evitar esto, ¡lo agradecería mucho! Gracias por señalar el problema principal: derivar Show. – gatoatigrado

+0

Bien, ahora creo que entiendo lo que estás tratando de hacer. Ver mi segunda respuesta. Manejará 3 + 4 + 2 correctamente. – MtnViewMark

+0

Puede usar la clase de tipos Monoid para esa funcionalidad "+". –

7

anulación de constructores enteros por defecto en Haskell para que produzcan cadenas

Así que esto se hace definiendo una instancia Num para String. Entonces (+) puede usarse como Cadena -> Cadena -> Cadena.

Un ejemplo super rápido:

{-# LANGUAGE TypeSynonymInstances #-} 

module A where 

instance Num String where (+) = (++) 

{- 

*A> "hello" + "world" 
"helloworld" 

-} 

escribir un método fromIntegral para obtener funciones de literales enteros a cadenas (por ejemplo, 1 -> "1").

Para un enfoque más general, más disciplinado al levantamiento de las listas de valores Num Num, ver el enfoque Hinze a corrientes como Num, http://hackage.haskell.org/package/hinze-streams

+0

Parece una buena solución, pero hace que ghci escuche un montón de advertencias ... y ¿cómo se ve esto desde la función Integral? ¡Muchas gracias! – gatoatigrado

5

Es esto lo que estamos tratando de hacer? Cree un tipo numérico para que pueda escribir expresiones en Haskell, y luego simplemente imprimirlas y hacer que salgan como cadenas de matemáticas LaTeX.

module Main where 

import Data.Ratio 

data LaTeXmath = E Precedence String 
    deriving (Eq) 

data Precedence = Pterm | Pmul | Padd | Pexp 
    deriving (Show, Eq, Ord, Bounded) 

expr :: Precedence -> LaTeXmath -> String 
expr p (E q s) | p >= q = s 
       | otherwise = "\\left(" ++ s ++ "\\right)" 

instance Num LaTeXmath where 
    a + b = E Padd (expr Padd a ++ " + " ++ expr Padd b) 
    a - b = E Padd (expr Padd a ++ " - " ++ expr Padd b) 
    a * b = E Pmul (expr Pmul a ++ " " ++ expr Pmul b) 

    negate a = E Pterm (" -" ++ expr Pterm a) 
    abs a = E Pterm (" |" ++ expr Pexp a ++ "| ") 
    signum a = E Pterm (" \\signum (" ++ expr Pexp a ++ ") ") 

    fromInteger i = E Pterm (show i) 

instance Fractional LaTeXmath where 
    a/b = E Pterm ("\\frac{" ++ expr Pexp a ++ "}{" ++ expr Pexp b ++ "}") 

    fromRational r = fromInteger num/fromInteger denom 
     where num = numerator r 
       denom = denominator r 

instance Show LaTeXmath where 
    show a = "\\[" ++ expr Pexp a ++ "\\]" 

sym :: String -> LaTeXmath 
sym x = E Pterm x 

anExample :: LaTeXmath 
anExample = sym "y"/(recip 2 * (3 + sym "x" + 2 * sym "y")) 

main :: IO() 
main = print anExample 

Esto se complica por la lógica necesaria para manejar la precedencia de modo que los paréntesis se inserten correctamente. El ejemplo se imprime:

\[\frac{y}{\frac{1}{2} \left(3 + x + 2 y\right)}\] 
Cuestiones relacionadas