Haskell:“show”的变体,不将 String 和 Char 用引号括起来

发布于 2024-09-04 07:50:33 字数 836 浏览 3 评论 0原文

我想要一个 show 的变体(我们称之为 label),它的作用就像 show 一样,只是它不包装 " " 中的 >String' ' 中的 Char。示例:

> 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 函数。

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

I'd like a variant of show (let's call it label) that acts just like show, except that it doesn't wrap Strings in " " or Chars in ' '. Examples:

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

I tried implementing this manually, but I ran into some walls. Here is what I tried:

{-# 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

However, because the default case's class overlaps instance Label [Char] and instance Label Char, those types don't work with the label function.

Is there a library function that provides this functionality? If not, is there a workaround to get the above code to work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一抹淡然 2024-09-11 07:50:33

上面的代码不起作用,因为仅根据“头”(即类名后面的部分)选择实例。 “上下文”,即 => 之前的内容,例如“Show 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

The code above isn't going to work because instances are chosen only based on the "head", that is, the part after the class name. The "context", the stuff before the => such as `Show a' is only examined afterwards. The context can eliminate an instance and produce a compiler error, but not cause the compiler to pick a different instance. Because of this behavior, overlapping instances are a potential ambiguity.

There are compiler extensions that can let you write more complicated instances, but I suspect you're probably best off just writing individual instances of your Label class. What purpose do you have in mind for this? Depending on what you're trying to accomplish, there might be something more special-purpose already out there.

Your example code is pretty simple, though--if you want, simply adding the OverlappingInstances extension should make it work with no further modifications. Using OverlappingInstances causes GHC to tolerate some ambiguity, so long as there's an obvious "most specific" instance. In your code, the two instances with concrete types are as specific as it gets, so there shouldn't be any problems.

Might as well add TypeSynonymInstances while you're at it, for better readability:

{-# 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
当梦初醒 2024-09-11 07:50:33

有一个 OverlappingInstances 语言扩展可以实现这一点。

There's an OverlappingInstances language extension which will make this work.

只是一片海 2024-09-11 07:50:33

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

是的。有一个相当新的库提供了有用的功能,例如 toS,其使用方式与 show 类似。 (查看文档

它可以与 string-conv 包下的 cabal 一起安装,如下所示: cabal install string-conv

参考:
黑客攻击

Is there a library function that provides this functionality?

Yes. There's a fairly new library that provides helpful functions, such as toS, which can be used similarly to show. (see docs)

It can be installed with cabal under the string-conv package like so: cabal install string-conv

Reference:
Hackage

独守阴晴ぅ圆缺 2024-09-11 07:50:33

这并不是您真正想要的,因为它为类型(Typeable)添加了额外的约束
但这是一般情况下可以做到的方法:

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

"1"

Data.Generics> (show `extQ` (id :: String -> String) `extQ` ((:[]) :: Char -> String)) "hello"

"hello"

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

"c"

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

"fl"

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

(显示 `extQ` (id :: String -> String) `extQ` ((:[]) :: Char -> String))
::(显示a,可输入a)=>一个->细绳

Not really what you want, since it adds an extra constraint to the type (Typeable)
but this is how you could do it generically:

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

"1"

Data.Generics> (show `extQ` (id :: String -> String) `extQ` ((:[]) :: Char -> String)) "hello"

"hello"

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

"c"

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

"fl"

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文