代码之家  ›  专栏  ›  技术社区  ›  bzim

实例实现的模式匹配

  •  3
  • bzim  · 技术社区  · 8 年前

    我正在尝试实现数据类型的show方法。

    data OptionList a b = EmptyOpt | OptionList { optListHead :: a, optListTail :: b } deriving (Read)
    
    instance (Show a, Show b) => Show (OptionList a b) where
        show (OptionList a EmptyOpt) = "{" ++ (show a) ++"}"
        show (OptionList EmptyOpt b) = "{" ++ (show b) ++"}"
        show (OptionList a b) = "{"++ (show a) ++ ", " ++ (show b) ++"}"
        show EmptyOpt = ""
    

    我希望选项列表不显示逗号,如果: a b 具有由EmptyOpt构造的值。但编译器显示以下错误:

    OptionList.hs:11:28:
        Couldn't match expected type ‘b’
                    with actual type ‘OptionList t0 t1’
          ‘b’ is a rigid type variable bound by
              the instance declaration at OptionList.hs:10:10
        Relevant bindings include
          show :: OptionList a b -> String (bound at OptionList.hs:11:9)
        In the pattern: EmptyOpt
        In the pattern: OptionList a EmptyOpt
        In an equation for ‘show’:
            show (OptionList a EmptyOpt) = "{" ++ (show a) ++ "}"
    
    OptionList.hs:12:26:
        Couldn't match expected type ‘a’
                    with actual type ‘OptionList t2 t3’
          ‘a’ is a rigid type variable bound by
              the instance declaration at OptionList.hs:10:10
        Relevant bindings include
          show :: OptionList a b -> String (bound at OptionList.hs:11:9)
        In the pattern: EmptyOpt
        In the pattern: OptionList EmptyOpt b
        In an equation for ‘show’:
            show (OptionList EmptyOpt b) = "{" ++ (show b) ++ "}"
    

    更新 :OptionList应该类似于无类型列表。

    (+:) :: a -> b -> (OptionList a b)
    infixr 5 +:
    t1 +: t2 = OptionList t1 t2
    

    因此,列表如下: 0 +: "test" +: True 将被定义为: OptionList Int (OptionList String (OptionList Bool EmptyOpt)) 而且会 show n as {0, {"test", {True}}}

    3 回复  |  直到 8 年前
        1
  •  6
  •   ase    8 年前

    您的更新的更新。 如果您愿意打开一些扩展,您可以使其工作:

    {-# LANGUAGE FlexibleInstances #-}
    
    data EmptyOpt = EmptyOpt
    
    data OptionList a b =
      OptionList a b
      deriving (Read)
    
    instance (Show a, Show b) => Show (OptionList a b) where
      show (OptionList a b) = "{ " ++ show a ++ ", " ++ show b ++ " }"
    
    instance {-# OVERLAPPING  #-} (Show a) => Show (OptionList a EmptyOpt) where
      show (OptionList a EmptyOpt) = "{ " ++ show a ++ " }"
    
    (+:) :: a -> b -> (OptionList a b)
    infixr 5 +:
    t1 +: t2 = OptionList t1 t2
    
    test = 0 +: "test" +: True +: EmptyOpt
    

    但就我个人而言,我会尝试做一些类似的事情

    data Option = B Bool | I Int | S String
    data OptionsList = Empty | OptionsList Option OptionsList
    

    你的问题是实例头( (Show a, Show b) => Show (OptionList a b) )表示您正在执行 Show 对于 OptionList a b 哪里 a b 有任何类型的 显示 实例,但在您的实现中,您需要 b 实际上是这类人 OptionList .

    也许您可以将类型更改为更像普通列表:

    data OptionList a
      = EmptyOpt
      | OptionList { optListHead :: a
                  ,  optListTail :: OptionList a}
      deriving (Read)
    

    然后您可以有一个实例:

    instance (Show a) => Show (OptionList a) where
      show (OptionList a EmptyOpt) = "{" ++ show a ++"}"
      show (OptionList a b) = "{"++ show a ++ ", " ++ show b ++"}"
      show EmptyOpt = ""
    
        2
  •  3
  •   willeM_ Van Onsem    8 年前

    问题是在实例声明中:

    instance (Show a, Show b) => Show (OptionList a b) where
        show (OptionList a EmptyOpt) = "{" ++ (show a) ++"}"
        show (OptionList EmptyOpt b) = "{" ++ (show b) ++"}"
        show (OptionList a b) = "{"++ (show a) ++ ", " ++ (show b) ++"}"
        show EmptyOpt = ""
    

    使用数据构造函数 因此,Haskell正确地推导出,您实际上定义了 show 结束 OptionList (OptionList c d) (OptionList e f) A:毕竟 EmptyOpt OptionList a b 所以 不能将这些用作参数 因为在实例的开头,您说要为 选项列表a b 带有泛型 a b .

    所以我不清楚你的目标是什么;将其修改为:

    instance (Show a, Show b, Show c, Show d) => Show (OptionList (OptionList a b) (OptionList c d)) where
    

    也不会有帮助,因为结构是递归的,因此您将定义具有无限递归深度的实例。

    在我看来,唯一合理的是,您的数据定义是错误的,应该是这样的:

    data OptionList a = EmptyOpt | OptionList { optListHead :: a, optListTail :: OptionList a }
    

    在这种情况下,您可以将其定义为:

    instance Show a => Show (OptionList a) where
        show (OptionList a b) = "{"++ show a ++ ", " ++ show b ++"}"
        show EmptyOpt = ""
    

    或者沿着这些线的东西。

        3
  •  0
  •   bzim    8 年前

    我的想法是创建一个类型独立的列表。这个列表的元素应该包含声明的任何类型。但我会放弃,做一些类似C联合的事情:

    data Option = OptStr String | OptInt Int | OptBool Bool