如何专门化(重载)单个类型的功能行为?

哈里斯·恩尼斯

我正在研究真实世界的Haskell,作为练习的一部分,我意识到我想要一个类似于的函数show :: Show(a) => a -> String,但该函数使Strings保持不变(而不是转义引号)。用伪代码,我想要的是:

show' :: String -> String
show' = id

show':: Show(a) => a -> String
show' = show

显然,这是行不通的(ghc抱怨多个类型签名和多个声明)。看来我应该改用typeclass。当我尝试编写此代码时,编译器会不断建议我添加更多语言扩展:

{-# LANGUAGE FlexibleInstances, UndecidableInstances, IncoherentInstances #-}

class Show' a where
  show' :: a -> String

instance Show' String where
  show' = id

instance (Show a) => Show' a where
  show' = show

-- x == "abc"
x = show' "abc"
y = show' 9

起初,这似乎行得通:x == "abc"并且y == "9"符合预期。但是,当我尝试在另一个多态函数中使用它时,编译器似乎总是将其解析为常规实现:

use :: (Show a) => a -> String
use x = show' x

-- z == "\"abc\""
z = use "abc"

因此,我在这里做错了事,我想知道是否有一种方法可以在没有大量语言扩展的情况下进行扩展(其中有些似乎不应该我不顾一切地使用)。如何show'使用现有show功能定义它

开支

根据OP的评论:

令我惊讶的是,如此简单的函数难以实现。

这根本不是一个简单的功能,因为它的排序违反了通常基于类型类的多态性保证。当我们看到一个实例

instance Show' a => Show' [a] where ...

我们通常假定所有实例都采用此实例,没有例外。对类型的普遍量化a确实意味着forall a

大卫在回答中指出,重叠/不连贯的实例打破了这一假设,并允许像您这样的“特殊案例”。这是一种可能的解决方案,但请注意,通过打破上述假设,重叠/不一致的实例会使实例解析变得非常脆弱,有时会导致意外地采用了错误的实例。

作为替代方案,您可以考虑利用Typeable我认为争议较小类型类:

import Data.Typeable

show' :: (Show a, Typeable a) => a -> String
show' x = case cast x of
   Just s  -> s           -- cast succeeded, it is a string
   Nothing -> show x      -- case failed, it is not a string

请注意Typeable,在类型中,存在的情况使人明显地发现此函数是使用即席多态性定义的,这使我们可以检查是否a一种类型,而这在参数多态性下通常是不可能的。

请注意,这并不需要IncoherentInstances也没有OverlappingInstances

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何测试是否存在模板功能专门化

来自分类Dev

C ++:数组的功能模板专门化

来自分类Dev

boost :: static_visitor无法使用多种可能的类型来专门化功能模板

来自分类Dev

使用类型特征专门化字符串迭代器的模板功能

来自分类Dev

使用decltype尾随返回类型来专门化功能模板

来自分类Dev

如何专门化模板子类?

来自分类Dev

如何专门化模板成员函数?

来自分类Dev

如何基于类型相关的类型专门化C ++模板类函数?

来自分类Dev

如何使C ++模板化函数与返回类型无关,以便将来进行专门化

来自分类Dev

如何使用type_traits或模板功能专门化来巩固模板方法

来自分类Dev

如何使用type_traits或模板功能专门化来巩固模板方法

来自分类Dev

模板专门化的不同编译器行为

来自分类Dev

部分专门化类型特征时,如何使用std :: decay?

来自分类Dev

如何在对象文字中专门化泛型类型?

来自分类Dev

如何专门化采用任何类型的模板以允许可变长度数组

来自分类Dev

如何在任意依赖类型上专门化模板

来自分类Dev

名称空间中的功能模板专门化

来自分类Dev

明确专门化功能模板的正确方法

来自分类Dev

模板指向功能的部分模板专门化

来自分类Dev

无法在线程中专门化功能模板

来自分类Dev

功能签名专门化<Arg [0] =拥有保证

来自分类Dev

无法专门化非通用类型'UIViewController'

来自分类Dev

返回类型对方法模板的专门化

来自分类Dev

为包含typedef的类型专门化模板

来自分类Dev

函数指针类型和值的部分类专门化

来自分类Dev

当类型是指针时,模板类方法专门化失败

来自分类Dev

返回类型对方法模板的专门化

来自分类Dev

是否有可能从具有专门化类型的类型派生并“专门化”具有专门类型的类型?

来自分类Dev

如何专门化模板类成员函数?

Related 相关文章

  1. 1

    如何测试是否存在模板功能专门化

  2. 2

    C ++:数组的功能模板专门化

  3. 3

    boost :: static_visitor无法使用多种可能的类型来专门化功能模板

  4. 4

    使用类型特征专门化字符串迭代器的模板功能

  5. 5

    使用decltype尾随返回类型来专门化功能模板

  6. 6

    如何专门化模板子类?

  7. 7

    如何专门化模板成员函数?

  8. 8

    如何基于类型相关的类型专门化C ++模板类函数?

  9. 9

    如何使C ++模板化函数与返回类型无关,以便将来进行专门化

  10. 10

    如何使用type_traits或模板功能专门化来巩固模板方法

  11. 11

    如何使用type_traits或模板功能专门化来巩固模板方法

  12. 12

    模板专门化的不同编译器行为

  13. 13

    部分专门化类型特征时,如何使用std :: decay?

  14. 14

    如何在对象文字中专门化泛型类型?

  15. 15

    如何专门化采用任何类型的模板以允许可变长度数组

  16. 16

    如何在任意依赖类型上专门化模板

  17. 17

    名称空间中的功能模板专门化

  18. 18

    明确专门化功能模板的正确方法

  19. 19

    模板指向功能的部分模板专门化

  20. 20

    无法在线程中专门化功能模板

  21. 21

    功能签名专门化<Arg [0] =拥有保证

  22. 22

    无法专门化非通用类型'UIViewController'

  23. 23

    返回类型对方法模板的专门化

  24. 24

    为包含typedef的类型专门化模板

  25. 25

    函数指针类型和值的部分类专门化

  26. 26

    当类型是指针时,模板类方法专门化失败

  27. 27

    返回类型对方法模板的专门化

  28. 28

    是否有可能从具有专门化类型的类型派生并“专门化”具有专门类型的类型?

  29. 29

    如何专门化模板类成员函数?

热门标签

归档