【问题标题】:Recursive instance definitions递归实例定义
【发布时间】:2012-10-25 02:34:14
【问题描述】:

我有一个递归数据定义:

data Checked a =  forall b. Checked (Either (Warning, Maybe (Checked b), a) a)

我需要递归地定义 Show:

instance (Show a) => Show (Checked a) where
  show (Right v) = show v
  show (Left (w, Nothing, v) = show w ++ show v
  show (Left (w, Just ch, v) = show w ++ show v ++ "caused by" ++ show ch --recursive here

GHC 给予

 Could not deduce (Show b) arising from a use of `show'
  from the context (Show a)
  bound by the instance declaration at Checked.hs:29:10-35
  Possible fix:
   add (Show b) to the context of
    the data constructor `Checked'
    or the instance declaration
  In the second argument of `(++)', namely `show ch'

如果我将 (Show b) 添加到实例定义的约束中,GHC 会给出:

 Ambiguous constraint `Show b'
  At least one of the forall'd type variables mentioned by the constraint
  must be reachable from the type after the '=>'
In the instance declaration for `Show (Checked a)'

我应该采取下一步来编译它吗?

【问题讨论】:

  • 请注意@HaskellElephant 已经更正了您的代码(实际上应该在答案中而不是在您的问题中发布)。
  • @AndrewC 我认为该错误与所提出的问题无关,因此我对其进行了更正。我应该恢复它吗? Sjoerd Visschers 的回答涵盖了该修复程序。
  • @HaskellElephant。我自己几乎将其还原,但想让您有机会将您的编辑作为答案的一部分。如果您还原它,请在 Sjoerd 的答案中添加一行以解释 Checked 应该在那里。 (目前尚不清楚 Sjoerd 看到的是原始版本还是编辑后的版本。)我认为在答案中编辑微不足道的明显错误是可以的,但如果你在不告诉提问者的情况下编辑问题,他们可能不会注意到,他们会被留在不必要的黑暗。如果您确实还原了它,请再次回复我,以便我删除我的 cmets。
  • @AndrewC 好吧,一件事是提问者的想法,但任何再次访问这篇文章以找出问题所在的人都会遇到额外的错误。请注意,不仅仅是额外的Checked,还有一个不匹配的括号和一个缺失的where,以及一个错误的缩进,它会在你遇到问题中的错误之前给你一个解析错误。我将恢复编辑并将其作为答案。
  • 对不起各位。自己纠正了那些草率的错误。把它归结为对精彩的stackoverflow不熟悉

标签: haskell


【解决方案1】:

您需要在数据类型中添加Show b 限制:

data Checked a = forall b. Show b => Checked (Either (Warning, Maybe (Checked b), a) a)

instance Show a => Show (Checked a) where
  show (Checked (Right v)) = show v
  show (Checked (Left (w, Nothing, v))) = show w ++ show v
  show (Checked (Left (w, Just ch, v))) = show w ++ show v ++ "caused by" ++ show ch

【讨论】:

  • 谢谢 Sjoerd,但有没有一种解决方案,我不必以这种方式用 Show 污染 Checked?因为现在编译器在其他 Checked 实例声明中要求 Show a => 约束,例如与Show无关的应用程序
  • @RobertOnslow 你能在没有存在量化的情况下进行管理吗? data Checked a b = ... 会吗?如果是这样,您将能够在没有 Show 上下文的情况下工作。或者,将整个事情包装在 GADT 中会解决您所有的麻烦吗?
  • @AndrewC 我先考虑一下 Checked a b。谢谢。
  • @RobertOnslow 您可以使用约束类型并在其他情况下传递无用的约束。用法见我的回答。
【解决方案2】:

Show 约束添加到数据类型定义中。

data Checked a =  forall b. Show b => Checked (Either (Warning, Maybe (Checked b), a) a)

你也可以使用约束类型

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ExistentialQuantification #-}

data Checked a c =  forall b. c b =>  Checked (Either (Maybe (Checked b c), a) a)

instance (Show a) => Show (Checked a Show) where
 show (Checked (Right v)) = show v
 show (Checked (Left (Nothing, v))) = show v
 show (Checked (Left (Just ch, v))) = show v ++ "caused by" ++ show ch

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    • 2013-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多