【问题标题】:Show a instance where a may already be a string显示 a 可能已经是字符串的实例
【发布时间】:2018-07-08 14:53:06
【问题描述】:

我正在研究一种容器类型,它基本上可以包含任何东西。像这样的:

data Foo a = Foo [a]

我正在为这种类型开发一个 Show 实例。

instance (Show a) => Show (Foo a) where
       show (Foo x) = concat $ map show x

这很好用:

show (Foo [1,2,3]) -- creates the string "123"
show (Foo [True, False]) -- creates the string "TrueFalse"

但是,有时 foo 中包含的“a”已经是一个字符串,因此调用“map show x”是不必要的。在字符串上调用 show 的结果是在其周围放置“”。

show (Foot ["A", "B"]) -- creates the string ""A""B""
-- what I'd like is the string "AB"

有没有办法为 (Foo String) 定义一个单独的 Show 实例?

【问题讨论】:

  • 这整个行业闻起来很腥。 Show 的目的是作为Read 的补充,因此读取您显示的内容应该是一个身份功能。在显示包含字符串的数据时打印原始字符串无论如何都是错误的。字符串可能包含各种不适合人类消费的杂物,并且会严重弄乱您的终端。 show 不仅添加了引号,而且避免了繁琐。
  • 我质疑你的说法,“调用'map show x'是不必要的”。您建议的替代输出 "AB" 会产生歧义:除了您的示例输入之外,Foo ["AB"]Foo ["","A","","","B"] 都会产生相同的输出。

标签: haskell show typeclass


【解决方案1】:

你不能在标准的 Haskell 中做这种事情。可以做到,但需要一点编译器黑魔法。我们将使用一些 GHC 扩展。

{-# LANGUAGE FlexibleInstances #-}

data Foo a = Foo [a]

instance (Show a) => Show (Foo a) where
    show (Foo x) = concat $ map show x

instance {-# OVERLAPS #-} Show (Foo String) where
    show (Foo x) = concat x

FlexibleInstances 让我们打破通常的实例规则并写入Show (Foo String),而通常我们应该只能写入Show (Foo a)。然后我们用{-# OVERLAPS #-} 注释前者,以抑制当Show (Foo a) 有多个重叠实例时发生的编译器错误。编译器足够聪明,可以选择更具体的实例,因此Foo String 将始终调用第二个实例,而Foo a 用于任何其他a 将调用第一个实例。

示例用法:

*Main> Foo [1, 2, 3]
123
*Main> Foo [True, False]
TrueFalse
*Main> Foo ["A", "B"]
AB

这种风格好吗?可能不是。我建议重新考虑您的策略并为字符串大小写提供不同的函数(例如,showFooString),因为像我们刚刚在上面所做的那样编写代码可能会使用户感到困惑。但是,如果您真的认为这是做您想做的事情的最佳方式,那就去做吧。请记住,您的代码只会使用 GHC 进行编译。

【讨论】:

    猜你喜欢
    • 2011-03-13
    • 1970-01-01
    • 1970-01-01
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多