gpt4 book ai didi

haskell - 另一个类的实例的 Show 实例

转载 作者:行者123 更新时间:2023-12-03 14:41:57 26 4
gpt4 key购买 nike

我有以下类(class):

class SappState s where
getTable :: s -> SymbolTable
getStack :: s -> Stack Scope
getScopeId :: s -> ScopeNum
getAst :: s -> Program
putTable :: SymbolTable -> s -> s
putStack :: Stack Scope -> s -> s
putScopeId :: ScopeNum -> s -> s
putAst :: Program -> s -> s

我总是 show data s 实例 this class与其中定义的功能。所以我用下面的代码概括了它:
instance (SappState s) => Show s where
show st = showT ++ showS ++ showI ++ showA
where
showT = getTable st ++ "\n"
showS = "Scope Stack:\n" ++ getStack st ++ "\n"
showI = "Scope Number:\t" ++ getScopeId st ++ "\n"
showA = getAst st ++ "\n"

但 GHC 给了我以下错误:
SappMonad.hs:87:27:
Illegal instance declaration for `Show s'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Show s'

我应该只使用 FlexibleInstances语用?我真的不明白它的作用以及它是否是正确的方式,或者我是否应该放弃概括 Show 的想法实例。

编辑

我激活了编译指示,它有这个新错误:
SappMonad.hs:88:10:
Constraint is no smaller than the instance head
in the constraint: SappState s
(Use -XUndecidableInstances to permit this)
In the instance declaration for `Show s'

我激活了 UndecidableInstances现在也是一个简单的 deriving Show将打破:
data Architecture = Arch
{ archName :: String
, types :: Map.Map DataType Bytes
} deriving (Show)

引发以下错误:
SappMonad.hs:39:17:
Overlapping instances for Show (Map.Map DataType Bytes)
arising from the 'deriving' clause of a data type declaration
Matching instances:
instance (Show k, Show a) => Show (Map.Map k a)
-- Defined in `containers-0.5.0.0:Data.Map.Base'
instance SappState s => Show s -- Defined at SappMonad.hs:89:10
When deriving the instance for (Show Architecture)

第二次编辑

我在该主题中搜索了更多内容,发现 OverlappingInstances ,添加了编译指示并编译,我认为它可以正常工作。但我觉得我在这些语言扩展方面走得太远了。 我怎样才能停止使用其中的一些并仍然获得相同的功能?

最佳答案

不幸的是,这个问题没有真正干净的解决方案。

您当前方法的最大缺点是是否有任何类似的 Show 的“自动”实例在程序的任何地方,它们都将完全停止工作,并且您将收到有关“重复实例”的错误。

基本问题是实例解析首先匹配实例声明的右侧。如果匹配,机器将提交该声明,然后尝试解决左侧所需的任何内容。

因此,在您的情况下,搜索 Show Foo 的实例对于任何 Foo将无条件匹配您的实例,如果找不到 SappState Foo,则解析将失败实例。
OverlappingInstances稍微减轻了这一点,因为它会首先寻找更具体的实例。所以Show Int将使用普通实例解决,因为它特别提到了 Int .但是如果有类似 instance SappState2 a => Show a也在范围内,然后是任何 Foo没有更具体的实例将导致重复实例错误。

我建议让 SappState 的实现者写一个Show手工实例。您可以通过提供实用功能来降低成本 showSappState :: SappState a => a -> String这样他们的实例就可以

instance Show Foo where
show = showSappState

[ Show 的正确实现|还有一些方法,但同样的通用方法适用]

如果您想确定 SappState 的所有实例也是 Show 的实例,您可以使用父类(super class)来强制执行此操作:
class Show a => SappState a where
...

实际上有一些建议可以自动实现父类(super class),这将完美地解决您的问题,但是在 GHC 中还没有实现任何东西。一个例子是 IntrinsicSuperclasses .

为了完整起见,值得一提的是 UndecidableInstances有点危险,因为它可能导致实例解析不终止。保证它将终止的规则必然有些保守,因为问题是图灵完备的,在某些情况下需要关闭它们。
instance SappState a => Show a 的问题是它减少了 Show aSappState a 的约束约束,并且没有明显的“进展”,因为正在搜索的新实例与旧实例的大小相同。想象一下如果有人也写了 instance Show a => SappState a 会发生什么.

关于haskell - 另一个类的实例的 Show 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25954934/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com