7

假设我想创建一个新的数据类型并使构造函数可显示,仅以小写而不是它们的大写定义。例如:

data Day = Monday | Tuesday | Wednesday| Thursday | Friday | Saturday | Sunday

通过添加派生 Show,ghci 会将它们打印为“星期一、星期二……等”。为了让它显示“星期一,星期二..等”,我尝试制作一个特殊的 show 实例:

import Data.Char

strToLower :: [Char] -> [Char]
strToLower (x:xs) = toLower x : strToLower xs
strToLower [] = []

instance Show Day where
   show d = strToLower (show d)

show 的第一次出现应该指定我新修改的 show 函数(每次打印时都会调用它),而第二次我打算使用 show 的正常派生版本,从构造函数名称获取字符串。

当然这不起作用(循环定义),因为 ghci 不知道我对“show”这个词的单独含义,但我不知道如何让他知道区别,因为两个版本都需要命名为 show ,第一个是因为这是 print 调用的,第二个是因为它是一个预定义的 haskell 函数,它可以从构造函数名称中给我一个字符串。我试过了

show d = strToLower ((showsPrec 0 d) "")

但这归结为相同的循环定义,至少这是我猜测的 ghci 陷入循环。

我理解为什么构造函数名称需要以大写字母开头,但显示它们小写不应该是一个问题,不是吗?我知道我可以为每个案例分别定义我的 show 函数,例如show Monday = "monday" show Tuesday = "tuesday"等,但我在这里只使用星期几作为示例,我的真实数据类型由 64 个构造函数组成,所以我认为它会更优雅以某种方式解决它。

是否可以深入研究 show 的 haskell 定义并更改该代码的副本?这是我能想到的唯一可能的解决方案,但如果可能的话,我不知道该怎么做。可能不是。所以其他解决方案也非常受欢迎!

感谢您抽出宝贵的时间,

Jelle(Haskell 初学者)

4

3 回答 3

12

您实际上可以使用TypeableData类来做到这一点。

为此,您需要DeriveDataTypeable扩展名,使用-XDeriveDataTypeable或通过将以下行放在定义您的类型的文件的开头来打开它:

{-# LANGUAGE DeriveDataTypeable #-}

您现在可以导入所需的模块:

import Data.Data
import Data.Typeable

并导出TypeableData

data Day = Monday | Tuesday | Wednesday| Thursday | Friday | Saturday | Sunday
     deriving (Typeable, Data)

现在您可以使用toConstr来获取构造函数表示:

instance Show Day where
   show = strToLower . showConstr . toConstr

但是请参阅其他答案,了解您是否真的想要,而不是简单地使用showDay函数或您自己的类型类。

于 2012-10-10T15:23:46.213 回答
6

该类的实例Show应该以这样一种方式工作,即您可以复制粘贴其输出并将其用作 Haskell 代码。如果您现在有小写构造函数,这些将无法正常工作。他们会采用这种newtype方法,

data DayInternal = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday

newtype Day = Day DayInternal
monday = Day Monday
tuesday = Day Tuesday
wednesday = Day Wednesday
thursday = Day Thursday
friday = Day Friday
saturday = Day Saturday
sunday = Day Sunday

instance Show Day where
    show (Day d) = strToLower $ show d

当然,这会给您留下您可能不喜欢的冗余。您可以使用 Template Haskell 自动构建它,但我怀疑这是否真的值得。

我真正认为的是你想要的根本不是一个Show实例,而是某种漂亮的打印。你可以自己动手

class MyNiceShow s where
  myNiceShow :: s -> String

data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
      deriving (Show)

instance MyNiceShow Day where
  myNiceShow d = strToLower $ show d
于 2012-10-10T13:44:24.673 回答
3

好吧,不知道您是否可以对相同的数据类型执行此操作,但是我可以看到的一种解决方法是将其包装为新类型

newtype D = D Day
instance Show D where
    show (D d) = strToLower $ show d

现在您可以使用 typeD而不是Day.

于 2012-10-10T13:31:28.183 回答