Haskell 如何";“显示”;小写的构造函数

Haskell 如何";“显示”;小写的构造函数,haskell,show,Haskell,Show,假设我想创建一个新的数据类型并使构造函数可以显示,只显示小写而不是大写定义。例如: data Day = Monday | Tuesday | Wednesday| Thursday | Friday | Saturday | Sunday 通过添加衍生节目,ghci会将它们打印为“星期一、星期二……等”,以使其显示为“星期一、星期二……等”,我尝试制作一个特殊的节目实例: import Data.Char strToLower :: [Char] -> [Char] strToLow

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

data Day = Monday | Tuesday | Wednesday| Thursday | Friday | Saturday | Sunday
通过添加衍生节目,ghci会将它们打印为“星期一、星期二……等”,以使其显示为“星期一、星期二……等”,我尝试制作一个特殊的节目实例:

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 tuday=“周二”
等等,但我在这里只使用一周中的几天作为示例,我的真实数据类型由64个构造函数组成,因此我认为以不同的方式解决它会更优雅

有没有可能深入研究haskell对show的定义并修改该代码的副本?这是我能想到的唯一可能的解决办法,但如果可能的话,我不知道怎么做。可能不会。因此,其他解决方案也非常受欢迎

谢谢你抽出时间


Jelle(Haskell初学者)

我们不知道是否可以对相同的数据类型执行此操作,但我可以看到一种解决方法,就是将其包装成一个新类型,如下所示

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

现在,您可以使用type
D
而不是
Day

类的
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
当然,这会给你留下你可能不喜欢的冗余。您可以使用模板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

实际上,您可以使用
Typeable
Data
类来实现这一点

要做到这一点,您需要
DeriveDataTypeable
扩展名,请使用
-XDeriveDataTypeable
将其打开,或者在定义您的类型的文件开头放置以下行:

{-# LANGUAGE DeriveDataTypeable #-}
您现在可以导入所需的模块:

import Data.Data
import Data.Typeable
并导出可键入的
数据

data Day = Monday | Tuesday | Wednesday| Thursday | Friday | Saturday | Sunday
     deriving (Typeable, Data)
现在,您可以使用
toConstr
获取构造函数表示:

instance Show Day where
   show = strToLower . showConstr . toConstr

但是,请查看其他关于您是否真的想这样做的答案,而不是简单地使用
showDay
函数或您自己的类型类。

为什么您不能编写
showDay=map toLower。show
和使用
showDay
而不是
show
?除了其他答案外,回答您的直接问题(我如何使用派生的
show
来实现我自己的
show
?)可能是值得的,对于这个问题,答案是“您不能”。Haskell的一条基本规则是,对于给定的类型,每个类最多只能有一个实例……代价是必须编写
(D Monday)
,而不是
Monday
。(当然不是说这是个坏主意,只是它有它的缺点。)@dave4420他当然可以定义一些其他函数而不是
show
,但是
show
实例可能被其他库函数使用,所以他不能仅仅修改它。这就是我所说的折衷,这就是为什么我说这是一种变通方法,需要为编写那些额外的构造函数付出一些代价因为你不能在它们上进行模式匹配,所以我认为大多数编写这些构造函数的工作都会在模式匹配中进行。另外,添加一个新的typeclass来编写show也是毫无用处的,因为你必须为其他类定义实例,或者直接使用函数,这就是dave建议的(编写myshow函数)。不,您可以定义
MyNiceShow
,以便对所有其他类型使用
Show
(使用#重叠实例,但嘿..).实际上,你也需要FlexibleInstances和undedicatableInstances,我试过了…如果你使用
MyNiceShow
对用户进行漂亮的打印,你可能会发现在大多数程序中,你想要使用的类型非常有限(特别是因为希望输出不采用Haskell语法的用户不喜欢许多内置的
Show
实例)。因此,为
MyNiceShow
创建一组实例并不需要太多的工作,而且您还可以获得额外的好处,即当您以后发现您想要更改其他类型的输出格式时,该类型已经有一个
Show
实例,这很容易。非常感谢!我更喜欢此解决方案,因为它很容易,并且保留了f“可展示”,而不必求助于“赝品”(my)show函数。再次感谢!不过,我不会构建这样一个
show
实例,因为它的输出不是有效的Haskell代码。但是这是定义
showDay
或自定义类型类显示函数+1的一种非常好的方法。-在一个不相关的注释中,编写
f$g$x