【问题标题】:Defining Show on an arbitrary recursive type in Haskell在 Haskell 中定义任意递归类型的 Show
【发布时间】:2011-12-16 22:37:28
【问题描述】:

我正在尝试使自定义类型成为 Show 的实例。

这里是 theType,它只是一个基本的 Set 类型。

data Set a = Insert a (Set a) | EmptySet

我想要类似的东西

Insert 1 (Insert 2 (Insert 3 EmptySet))

显示类似

{1, 2, 3}

我该怎么做?我尝试用字符串连接来做,但似乎做字符串插值被认为是不好的形式(Haskell 似乎本身并不支持这个?)另外,我如何在列表中获得花括号?到目前为止,我能做的就是这个,它基本上什么都不做......

instance (Show a) => Show (Set a) where
     show EmptySet = ""
     show (Insert a as) = show a ++ show as 

另外,我尝试使用 Hoogle 和 Hayoo 来查找 List 实现,这样我就可以看到它是如何在 List 上实现的。我找不到它。有人对此有任何指示吗?我尝试搜索“show::[a]->String”、“Data.Lists”、“Lists”等......

【问题讨论】:

  • 顺便说一句,这可能是个坏主意。 show 的结果应该是有效的 Haskell 代码,它产生的值等于传递给 show 的值。我建议定义一个 fromList 函数并在集合 {1, 2, 3} 上制作 show 产生例如fromList [1, 2, 3];这是标准 Data.Map 和 Data.Set 库所采用的方法。或者,您可以定义自己的函数来执行此操作,而不是调用 show 来查看此表示法中的集合。

标签: haskell typeclass


【解决方案1】:

这是一个直接递归的解决方案:

instance Show a => Show (Set a) where
  show = ('{' :) . go
    where
      go EmptySet            = "}"
      go (Insert x EmptySet) = show x ++ "}"
      go (Insert x xs)       = show x ++ ", " ++ go xs

如果你不喜欢(++)的低效使用,当然可以使用difference lists

instance Show a => Show (Set a) where
  show = ('{' :) . ($ []) . go
    where
      go EmptySet            = ('}' :)
      go (Insert x EmptySet) = shows x . ('}' :)
      go (Insert x xs)       = shows x . (", " ++) . go xs

应该这样做;所以,让我们测试一下:

> show (Insert 2 (Insert 3 (Insert 5 EmptySet)))
"{2, 3, 5}"

【讨论】:

  • 如果你不喜欢(++)的低效使用,你应该使用showsPrec而不是show
  • @SjoerdVisscher:我当然同意,但我想通过第一个实现来演示增量。
【解决方案2】:

你的那种类型仍然与列表同态。无论在哪里定义 Show 实例;你仍然可以使用它:

toList (Insert a b) = a:toList b
toList EmptySet = []

instance Show a => Show (Set a) where
    show = show . toList

【讨论】:

    【解决方案3】:

    数据类型可能是递归的,但这不是函数递归的理由。

    import Data.List (intercalate)
    
    instance Show a => Show (Set a) where
      show x = "{" ++ intercalate ", " (toList x) ++ "}"
    

    这假设你有一个函数toList :: Set a -> [a]。递归隐藏在那里。

    List 实现是通过Show typeclass 中的showList 函数完成的(因此Strings,又名[Char]s,可以以不同方式显示)。

    【讨论】:

    • 我是个菜鸟,但这不是因为列表必须包含所有相同类型的元素吗?如果我将一个数字列表输入这个函数,它不会引发类型错误吗?
    • 您定义的集合还必须包含相同类型的元素。在Insert a (Set a),都是as。所以应该没有问题。
    猜你喜欢
    • 2019-05-07
    • 1970-01-01
    • 2021-12-28
    • 1970-01-01
    • 2012-03-22
    • 1970-01-01
    • 2015-09-08
    • 2018-09-10
    • 1970-01-01
    相关资源
    最近更新 更多