Как переопределить показ для нового типа? - PullRequest
6 голосов
/ 18 апреля 2010

Я хочу переопределить целочисленные конструкторы по умолчанию в Haskell, чтобы они производили строки (в основном для любопытства, но временно, чтобы сделать хорошую альтернативу ввода для неудобства \ frac {} {} LaTeX).

Я хотел иметь возможность использовать сам язык вместо специального синтаксического анализатора, но, наверное, это не сработает ...

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

Проблема с вышеупомянутым состоит в том, что функция + работает только для (A, A) вместо (A, String) и т. Д. Если кто-то просто пропускает совпадение с образцом "(A a)" и пишет "a" вместо этого функция show () добавляет «A», поэтому «3» становится «A 3» вместо «3».

Я хочу переопределить Show для A, но, похоже, это головная боль ...

Ответы [ 3 ]

14 голосов
/ 18 апреля 2010

Если вам нужен собственный экземпляр Show для A, просто не извлекайте его и создайте свой собственный экземпляр:

newtype A = A Int deriving (Eq, Num)

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

Тогда вы можете написать что-то вроде:

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

Конечно, если вы определяете свой собственный оператор + таким образом, то я не думаю, что ваша проблема требует объявления 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
7 голосов
/ 18 апреля 2010

переопределяет целочисленные конструкторы по умолчанию в Haskell, чтобы они генерировали строки

Так что это делается путем определения экземпляра Num для String. Тогда (+) можно использовать как String -> String -> String.

Супер быстрый пример:

{-# LANGUAGE TypeSynonymInstances #-}

module A where

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

{-

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

-}

Напишите метод fromIntegral для получения функций из целочисленных литералов в строки (например, 1 -> «1»).

Для более общего, более дисциплинированного подхода к поднятию списков значений Num в Num, см. Подход Хинце к потокам как Num, http://hackage.haskell.org/package/hinze-streams

5 голосов
/ 18 апреля 2010

Это то, что вы пытаетесь сделать? Создать числовой тип, чтобы вы могли писать выражения в Haskell, а затем просто напечатать их и сделать их математическими строками 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

Это усложняется логикой, необходимой для обработки приоритета, чтобы круглые скобки были вставлены правильно. Пример распечатывает:

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