Как переопределить шоу для нового типа?

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

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

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, но это кажется довольно головной болью...


person gatoatigrado    schedule 18.04.2010    source источник


Ответы (3)


Если вам нужен собственный экземпляр 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
person MtnViewMark    schedule 18.04.2010
comment
Спасибо, но это не очень композиционно: 3 + 4 + 2 дает «3 + 4 + 2». Извините за то, что я такой новичок ... если вы знаете способ обойти это, я был бы очень признателен! Спасибо, что указали на основную проблему — получение Show. - person gatoatigrado; 18.04.2010
comment
Хорошо, теперь я думаю, что понимаю, что вы пытаетесь сделать. Смотрите мой второй ответ. Он будет обрабатывать 3 + 4 + 2 правильно. - person MtnViewMark; 18.04.2010
comment
Вы можете использовать класс типов Monoid для этой + функциональности. - person Dalibor Filus; 12.02.2016

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

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

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

{-# LANGUAGE TypeSynonymInstances #-}

module A where

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

{-

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

-}

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

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

person Don Stewart    schedule 18.04.2010
comment
Это выглядит хорошим решением, но заставляет ghci выдавать много предупреждений... и как выглядит эта функция fromIntegral? Большое спасибо! - person gatoatigrado; 18.04.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)}\]
person MtnViewMark    schedule 18.04.2010