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

Haskell类型类速记

  •  22
  • rampion  · 技术社区  · 17 年前

    所以,我有一对类型类,我将在一起使用很多,我希望避免每次都指定这两个类型。基本上,而不是

    :: (Ord a, Fractional a, Ord b, Fractional b, ... Ord z, Fractional z) =>
    

    在所有类型规范的开头,我宁愿

    :: (OrdFractional a, OrdFractional b, ... OrdFractional z)
    

    所以,我最初的想法是如何做到这一点,只是声明一个新的typeclass

    module Example where
    
    class (Fractional a, Ord a) => OrdFractional a
    
    example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool
    example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3)
    

    但这并不像我希望的那样自动工作:

    % ghci
    Prelude> :l Example.hs
    Ok, modules loaded: Example.
    Prelude Example> example (1::Float,3::Float) (2,2) (3,1)
    
    <interactive>:1:0:
        No instance for (OrdFractional Float)
          arising from a use of `example' at <interactive>:1:0-39
        Possible fix:
          add an instance declaration for (OrdFractional Float)
        In the expression: example (1 :: Float, 3 :: Float) (2, 2) (3, 1)
        In the definition of `it':
            it = example (1 :: Float, 3 :: Float) (2, 2) (3, 1)
    

    手动创建实例似乎是一种拖拽,因此,接下来,我想我可能会尝试自动创建实例:

    module Example where
    
    class OrdFractional a
    instance (Fractional a, Ord a) => OrdFractional a
    
    example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool
    example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3)
    

    但是编译器不喜欢这样:

    ghc -c Example.hs
    
    Example.hs:4:0:
        Illegal instance declaration for `OrdFractional a'
            (All instance types must be of the form (T a1 ... an)
             where a1 ... an are 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 `OrdFractional a'
    

    有什么方法可以做到吗?

    4 回复  |  直到 13 年前
        1
  •  32
  •   javawizard    13 年前

    在ghc 7.4中引入了constraintkinds扩展后,约束现在是一种类型 Constraint ,因此可以使用普通类型的同义词来获取所需的内容:

    {-# LANGUAGE ConstraintKinds #-}
    
    type OrdFractional a = (Ord a, Fractional a)
    
        2
  •  11
  •   CesarB    17 年前

    您需要的是类别名。有人提议将其添加到haskell http://repetae.net/recent/out/classalias.html

        3
  •  10
  •   ephemient    16 年前

    当编译器说 Use -XFlexibleInstances “,您应该尝试添加

    {-# LANGUAGE FlexibleInstances #-}
    

    到源代码的顶部(当然,还可以阅读文档了解它的作用!).

    在这种特定的情况下,这将使您的代码工作:

    {-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
    

    为了启用 => 实例头上的上下文和不可确定的实例是必需的,因为编译器在处理 OrdFractional a 上下文,不能结束添加 Fractional a Ord a 对于上下文——这对最终确定 a 在适当的糟糕情况下,类型检查可能会出现分歧;编译器确实不喜欢这种情况。(如果编译器永远运行或内存不足,您可能也不会喜欢它。)

        4
  •  3
  •   Martijn    16 年前

    不。

    表示其他类的超类的解决方案最接近于您希望在Haskell中实现的。尽管这需要手动执行该新类的实例,但有时也会使用它,例如在 rewriting 图书馆。

    正如cesarb提到的,类别名可以满足您的需要(以及更多),但它们只是一个多年来一直存在且从未实现的建议,可能是因为它存在许多问题。相反,各种各样的其他提议也应运而生,但这些提议都没有得到实施。(有关这些建议的列表,请参阅 Haskellwiki page .)其中一个项目 Hac5 是要修改ghc以包含一个小的类别名子集 上下文同义词 (这正是你在这里所要求的,没有更多),但遗憾的是,它从来没有完成。

    推荐文章