【问题标题】:How does one override show for a newtype?一个覆盖如何显示新类型?
【发布时间】:2010-04-18 01:46:44
【问题描述】:

我想覆盖 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”,而不仅仅是“3”。

我想覆盖A的Show,但是好像挺头疼的……

【问题讨论】:

    标签: haskell show typeclass


    【解决方案1】:

    如果您想要自己的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
    

    【讨论】:

    • 谢谢,但它不是很组合:3 + 4 + 2 产生'"3 + 4" + 2'。很抱歉成为这样的新手...如果您知道解决此问题的方法,我将不胜感激!感谢您指出主要问题——导出 Show。
    • 好的 - 现在我想我明白你想要做什么了。请参阅我的第二个答案。它将正确处理 3 + 4 + 2。
    • 您可以使用 Monoid 类型类来实现“+”功能。
    【解决方案2】:

    覆盖 Haskell 中的默认整数构造函数,以便它们生成字符串

    所以这是通过为 String 定义一个 Num 实例来完成的。然后 (+) 可以用作 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

    【讨论】:

    • 这看起来是一个不错的解决方案,但它让 ghci 吐出很多警告......这个 fromIntegral 函数看起来如何?非常感谢!
    【解决方案3】:

    这是你想要做的吗?创建一个数字类型,以便您可以在 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)}\]
    

    【讨论】:

      猜你喜欢
      • 2019-02-27
      • 2012-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-09
      • 1970-01-01
      • 2017-04-13
      • 2011-01-20
      相关资源
      最近更新 更多