Haskell 多个重叠实例的交互
模块Haskell 多个重叠实例的交互,haskell,functional-programming,overlapping-instances,Haskell,Functional Programming,Overlapping Instances,模块Type.hs定义同音词newtype,并仅导出其类型构造函数,而不导出值构造函数,以避免暴露细节;它还提供了一个构造函数makeType,以平衡缺少值的情况。为什么需要将字符串包装为新类型?因为我希望它不仅仅是一个字符串;在我的特定情况下,Type实际上被称为Line,与makeType相对应的内容强制它只包含一个\n,作为最后一个字符。对我来说,newtype似乎是最明显的选择。如果不是这样,请原谅我:我正在学习 模块类型(类型,makeType),其中 newtype=类型字符串 ma
Type.hs
定义同音词newtype
,并仅导出其类型构造函数,而不导出值构造函数,以避免暴露细节;它还提供了一个构造函数makeType
,以平衡缺少值的情况。为什么需要将字符串
包装为新类型?因为我希望它不仅仅是一个字符串
;在我的特定情况下,Type
实际上被称为Line
,与makeType
相对应的内容强制它只包含一个\n
,作为最后一个字符。对我来说,newtype
似乎是最明显的选择。如果不是这样,请原谅我:我正在学习
模块类型(类型,makeType),其中
newtype=类型字符串
makeType::字符串->类型
makeType=Type
为了以我喜欢的方式显示类型为type
的值(例如,考虑到我实际使用的Line
,我可能想用一个漂亮的unicode字符或序列来表示\n
,或者其他任何东西),我创建了另一个模块TypeShow.hs
,稍后我将使用它(在尝试做我所描述的事情时)我通过添加一些pragma进行编辑。为什么是另一个模块?因为我猜内部的工作方式和我向屏幕显示的方式是两个独立的方面。我错了吗
{-#语言灵活实例}
模块类型显示()其中
导入类型
实例显示类型在哪里
显示=常量“类型”
--下面的例子是后来出现的,请参见下文
实例{-#重叠{-}显示(可能是类型)其中
show(Just t)=show t
显示
除了这对模块(描述Type
的核心,以及它应该如何显示)之外,我还创建了其他类似的模块对Type1
/Type1Show
,Type2
/Type2Show
,它们都包装了一个String
,以表示和显示其他类似String
的实体
出于其他原因,我还需要另一种类型来包装可选值,它可以是type
、Type1
,或者任何其他类型,所以我编写了这个模块
modulewrapper(Wrapper、makeWrapper、getInside)其中
newtype包装器a=包装器{getInside::可能是a}
makeWrapper::a->Wrapper a
makeWrapper=Wrapper.Just
(在实际<代码>包装器< /代码>中实际上包装了不止一个<代码>类型值,但是我将避免添加更多的细节,必要时;如果下面是愚蠢的,因为我在
的细节,同时提供Wrapper
来制作一个,以及makeWrapper
来对其内部进行“受控”访问getInside
WrapperShow.hs
模块,以便Wrapper
的show
方法依赖于内容的show
方法
模块包装器显示()其中
导入包装器
实例Show a=>Show(包装器a)其中
show=show.getInside
然而,此时,当类型a
是可能类型
时,我想显示包装的内容
打印一个空字符串,而不是什么都没有
,或者的内容只是
;因此我编写了上面注释的实例show(可能类型)
鉴于此,
Type“hello”
和Just$Type“hello”
都正确显示为Type
,但是Wrapper$Just$Type“hello”
显示为Just Type
,就像它使用Maybe
的Show
的原始实例一样,而不考虑Maybe
中的该特定类型(即Type
)我已经定制了Show
实例。在Show
实例声明中,对于Wrapper
,我们并不知道a
是什么。但是显然,我们必须已经选择了Show
实例用于可能是a
。根据可用的信息,唯一匹配的实例是默认的showa=>Show(可能是a)
,它不需要具体的a
GHC用户指南中提到了“推迟”实例选择的概念:
这将选择哪个实例的问题推迟到调用站点
对于f,到那时对类型b的了解更多。你可以写这个
如果使用FlexibleContexts扩展名,请自己键入签名
及
实例声明本身可能会出现完全相同的情况[…]解决方案是通过向实例声明的上下文添加约束来推迟选择
我们可以尝试这样一个技巧。与其要求Show a
,不如要求整个Show(可能是a)
。现在Show
实例被视为“给定”,我们不会做出局部决定。我想这会延迟Show(可能是a)的选择
实例调用像print$Wrapper$Just$type3
这样的站点,在这里我们有更多关于a
具体类型的信息
检验这一假设:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
newtype Type = Type Int
instance Show Type where
show = const "Type"
instance {-# OVERLAPS #-} Show (Maybe Type) where
show (Just t) = show t
show _ = ""
newtype Wrapper a = Wrapper (Maybe a)
instance Show (Maybe a) => Show (Wrapper a) where
show (Wrapper edit) = show edit
main :: IO ()
main = print $ Wrapper $ Just $ Type 3
-- output: Type
也就是说,我发现这种行为令人困惑,并将在生产代码中避开它
正如@dfeuer在注释和链接代码中指出的,重叠实例是有问题的。例如,如果我们将此无辜函数添加到此答案的代码中:
foo :: Show a => Maybe a -> String
foo = show
模块停止编译:
* Overlapping instances for Show (Maybe a)
arising from a use of `show'
Matching instances:
instance Show a => Show (Maybe a) -- Defined in `GHC.Show'
instance [overlap ok] Show (Maybe Type) -- Defined at Main.hs:14:27
(The choice depends on the instantiation of `a'
但是现在我很困惑。为什么在最初的问题中,实例定义Show(Wrapper a)
没有发生完全相同的类型错误
编译失败的原因似乎是描述中的最后一个要点