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

向Haskell中实例声明的上下文添加类型约束

  •  7
  • highBandWidth  · 技术社区  · 14 年前

    我试图表示加权边。我最终希望OutE是Eq和Ord的一个实例,而etype是Eq和Ord的一个实例。假设我有以下temp.hs文件:

    data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype}
    
    applyFunBy accessor ordfun = (\x y -> (ordfun (accessor x) (accessor y)))
    
    instance Eq (OutE vtype etype) where
        --(==) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool
        --(/=) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool
        (==) = applyFunBy edgeValue (==)
        (/=) = applyFunBy edgeValue (/=)
    

    在ghci中加载时,会出现以下错误:

    temp.hs:10:19:
        Could not deduce (Ord etype)
          from the context (Eq (OutE vtype etype))
          arising from a use of `edgeValue' at temp.hs:10:19-27
        Possible fix:
          add (Ord etype) to the context of the instance declaration
        In the first argument of `applyFunBy', namely `edgeValue'
        In the expression: applyFunBy edgeValue (==)
        In the definition of `==': == = applyFunBy edgeValue (==)
    
    temp.hs:11:19:
        Could not deduce (Ord etype)
          from the context (Eq (OutE vtype etype))
          arising from a use of `edgeValue' at temp.hs:11:19-27
        Possible fix:
          add (Ord etype) to the context of the instance declaration
        In the first argument of `applyFunBy', namely `edgeValue'
        In the expression: applyFunBy edgeValue (/=)
        In the definition of `/=': /= = applyFunBy edgeValue (/=)
    Failed, modules loaded: none.
    

    如果包含(==)和(\=)的类型签名行,我将得到:

    temp.hs:6:1:
        Misplaced type signature:
        == ::
          (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool
    
    temp.hs:7:1:
        Misplaced type signature:
        /= ::
          (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool
    
    2 回复  |  直到 13 年前
        1
  •  6
  •   Dario    14 年前

    你限制了 etype 成为 Ord 在定义中 OutE :

    data (Ord etype) => OutE vtype etype = ...
    

    但是在 Eq 实例,实际上您正在尝试为 任何 etype类型 肆无忌惮。

    instance Eq (OutE vtype etype) where
    

    当然这不管用,因为 外线 它的定义就是 Ord etype s、 因此,还必须将typeclass约束添加到实例定义中。

    instance (Ord etype) => Eq (OutE vtype etype) where
    

    注意,其中一个定义 == /= 足够typeclass工作了。


    请注意,不使用typeclass约束通常更容易,因此被认为是更好的样式 data -类型,但仅限于实际需要typeclass功能的实例/方法。

    在许多情况下,不需要约束,只会得到不必要的笨拙类型签名。

    例如,一些有序的映射类型 Ord key => Map key value .

    如果我们只想列出所有的钥匙呢?或者得到元素的数目?我们不需要钥匙 作战需求文件 对于这些,为什么不让地图不受限制

    getKeys :: Map key value -> [key]
    getLength :: Map key value -> Int
    

    当我们真正需要typeclass时,只需在函数中添加它

    insert :: Ord key => key -> value -> Map key value
    
        2
  •  2
  •   Thomas M. DuBuisson    14 年前
    data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype}
    

    第一个问题:这是消费坏风格。数据类型声明不应具有约束。将约束留给函数,就像containers包那样。

    instance Eq (OutE vtype etype) where
    

    第二个“问题”。你可以加上 deriving (Eq) 在你的数据声明之后。我猜你知道这一点,并且正在为自己的学习明确地编写实例(对你有好处)。。。

    instance Eq (OutE vtype etype) where
        (==) = applyFunBy edgeValue (==)
        (/=) = applyFunBy edgeValue (/=)
    

    第三个问题:如果股票的价值是 Eq 上课。所以你想说 etype 受等式约束:

    instance (Eq etype) => Eq (OutE vtype etype) where
        (==) = applyFunBy edgeValue (==)
        (/=) = applyFunBy edgeValue (/=)
    

    第四,实际上不需要同时为(=)和(/=)编写实例。一旦您定义了其中一个,默认值将起作用。