给定Dynamic
类型的变量,可以利用内部变量的类型类而不调整确切的类型?例如,假设我想写一个函数prettyShow
。如果内部类型是Show
的实例,那么我们应该使用该实例;否则,我们应该使用Dynamic
类的实例。在代码中,这可能如下所示:
prettyShow :: Dynamic -> String
prettyShow x = case fromDynamic x :: (forall a. Show a => Maybe a) of
Nothing -> show x
Just y -> show y
编辑:由于看起来无法直接完成,可以采取哪些好的解决方法?
答案 0 :(得分:6)
这可以使用open-typerep库中Dynamic
的实现来完成(如果您接受使用泛型编程和大量GHC扩展)。
{-# LANGUAGE TypeOperators #-}
import Data.TypeRep
type Types = BoolType :+: IntType :+: ListType
x, y :: Dynamic Types
x = toDyn [False,True]
y = toDyn [1, 2 :: Int]
test1 = show x
test2 = show y
show
的定义很简单,您可以使用该库来定义动态值上的其他函数。
在上面的例子中,我使用了封闭式宇宙Type
。但是,使用数据类型单点技巧,您还可以定义开放Universe的功能。例如,show
本身是开放的。
<强>性能
simple benchmark表示,对于上面使用的小型Universe,此Dynamic
比Data.Dynamic
中的base
慢2-3倍。将Universe增加到30个类型构造函数会使它慢一点多10倍。
自动推导新类型
open-typerep
支持从少量预定义表示类型中创建Universe。原则上应该可以使用TemplateHaskell自动派生新类型的表示,但为Witness
和PWitness
生成正确的实例将会很棘手,因为这些实例取决于可用的其他实例。 (例如Witness
Show
实例使用了Dynamic
。