3

我想要一个show(让我们称之为label)的变体,它的行为就像show,除了它不包含Strings in" "Chars in ' '。例子:

> label 5
"5"
> label "hello"
"hello"
> label 'c'
"c"

我尝试手动实现此功能,但遇到了一些问题。这是我尝试过的:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
module Label where

class (Show a) => Label a where
    label :: a -> String

instance Label [Char] where
    label str = str

instance Label Char where
    label c = [c]

-- Default case
instance Show a => Label a where
    label x = show x

但是,由于默认情况的类与 和 重叠instance Label [Char],因此instance Label Char这些类型不适用于该label函数。

是否有提供此功能的库函数?如果没有,是否有解决方法可以使上述代码正常工作?

4

4 回答 4

5

上面的代码不起作用,因为仅根据“head”选择实例,即类名后面的部分。“上下文”,即=>“显示 a”之前的内容仅在之后检查。上下文可以消除实例并产生编译器错误,但不会导致编译器选择不同的实例。由于这种行为,重叠的实例是一种潜在的歧义。

有一些编译器扩展可以让您编写更复杂的实例,但我怀疑您最好只编写Label类的单个实例。你对此有什么想法?根据您要完成的工作,可能已经有一些更特殊的用途。

不过,您的示例代码非常简单——如果您愿意,只需添加OverlappingInstances扩展名即可使其无需进一步修改即可工作。OverlappingInstances只要有一个明显的“最具体”的实例,使用会导致 GHC 容忍一些歧义。在您的代码中,具有具体类型的两个实例尽可能具体,因此不应该有任何问题。

TypeSynonymInstances为了更好的可读性,不妨在使用时添加:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Label where

class (Show a) => Label a where
    label :: a -> String

instance Label String where label x = x

instance Label Char where label x = [x]

instance (Show a) => Label a where label = show
于 2010-06-04T02:37:58.713 回答
1

有一个OverlappingInstances语言扩展可以完成这项工作。

于 2010-06-04T02:41:09.697 回答
1

是否有提供此功能的库函数?

是的。有一个相当新的库提供了有用的功能,例如toS,它可以与show. (见文档

它可以使用 cabal 在 string-conv 包下安装,如下所示:cabal install string-conv

参考: 黑客攻击

于 2015-06-19T19:54:30.960 回答
0

不是你真正想要的,因为它为类型(Typeable)添加了一个额外的约束,但这是你通常可以做到的:

Data.Generics> (显示 `extQ` (id :: String -> String) `extQ` ((:[]) :: Char -> String)) 1

“1”

Data.Generics> (显示 `extQ` (id :: String -> String) `extQ` ((:[]) :: Char -> String)) "你好"

“你好”

Data.Generics> (显示 `extQ` (id :: String -> String) `extQ` ((:[]) :: Char -> String)) 'c'

“C”

Data.Generics> (show `extQ` (id :: String -> String) `extQ` ((:[]) :: Char -> String)) ['f','l']

“飞”

Data.Generics> :t (显示 `extQ` (id :: String -> String) `extQ` ((:[]) :: Char -> String))

(show `extQ` (id :: String -> String) `extQ` ((:[]) :: Char -> String)) :: (Show a, Typeable a) => a -> String

于 2010-06-08T11:07:54.777 回答