Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell ConstraintKinds在一个超级简单的示例中进行了解释_Haskell_Ghc_Type Kinds_Constraint Kinds - Fatal编程技术网

Haskell ConstraintKinds在一个超级简单的示例中进行了解释

Haskell ConstraintKinds在一个超级简单的示例中进行了解释,haskell,ghc,type-kinds,constraint-kinds,Haskell,Ghc,Type Kinds,Constraint Kinds,什么是a 为什么会有人(在实践中)使用它 它有什么好处 您能给出一个简单的代码示例来说明前两个问题的答案吗 例如,为什么在代码中使用它?好吧,我将提到它允许您做的两件实际事情: 通过类型类约束参数化类型 编写允许其实例指定所需约束的类型类 也许最好用一个例子来说明这一点。Haskell的一个经典缺点是,不能为对其类型参数施加类约束的类型创建Functor实例;例如,containers库中的Set类,需要对其元素进行Ord约束。原因是在“香草”Haskell中,必须对类本身进行约束: class

什么是a

为什么会有人(在实践中)使用它

它有什么好处

您能给出一个简单的代码示例来说明前两个问题的答案吗


例如,为什么在代码中使用它?

好吧,我将提到它允许您做的两件实际事情:

  • 通过类型类约束参数化类型
  • 编写允许其实例指定所需约束的类型类
  • 也许最好用一个例子来说明这一点。Haskell的一个经典缺点是,不能为对其类型参数施加类约束的类型创建
    Functor
    实例;例如,
    containers
    库中的
    Set
    类,需要对其元素进行
    Ord
    约束。原因是在“香草”Haskell中,必须对类本身进行约束:

    class OrdFunctor f where
        fmap :: Ord b => (a -> b) -> f a -> f b
    
    …但该类仅适用于特别需要
    Ord
    约束的类型。不是一个普遍的解决办法

    那么,如果我们可以使用该类定义并抽象掉
    Ord
    约束,允许单个实例说出它们需要什么约束,会怎么样?嗯,
    ConstraintKinds
    plus
    TypeFamilies
    允许:

    {-# LANGUAGE ConstraintKinds, TypeFamilies, FlexibleInstances #-}
    
    import Prelude hiding (Functor(..))
    import GHC.Exts (Constraint)
    import Data.Set (Set)
    import qualified Data.Set as Set
    
    -- | A 'Functor' over types that satisfy some constraint.
    class Functor f where
       -- | The constraint on the allowed element types.  Each
       -- instance gets to choose for itself what this is.
       type Allowed f :: * -> Constraint
    
       fmap :: Allowed f b => (a -> b) -> f a -> f b
    
    instance Functor Set where
        -- | 'Set' gets to pick 'Ord' as the constraint.
        type Allowed Set = Ord
        fmap = Set.map
    
    instance Functor [] where
        -- | And `[]` can pick a different constraint than `Set` does.
        type Allowed [] = NoConstraint
        fmap = map
    
    -- | A dummy class that means "no constraint."
    class NoConstraint a where
    
    -- | All types are trivially instances of 'NoConstraint'.
    instance NoConstraint a where
    
    (请注意,这不是将
    函子
    实例设置为
    的唯一障碍;另请参见。)

    不过,这种解决方案还没有被普遍采用,因为
    ConstraintKinds
    或多或少还是一种新特性


    ConstraintKinds
    的另一个用途是通过类约束或类参数化类型。我将复制:

    对象
    类型所做的是两个功能的组合:

  • 一种存在类型(此处由
    GADTs
    启用),它允许我们在同一
    对象
    类型中存储异构类型的值
  • ConstraintKinds
    ,它允许我们将
    对象
    硬编码到某些特定的类约束集,而不是让
    对象
    类型的用户指定他们想要作为
    对象
    类型参数的约束
  • 现在,我们不仅可以创建
    Shape
    实例的异构列表:

    data Circle = Circle { radius :: Double }
                deriving Typeable
    
    instance Shape Circle where
      getArea (Circle radius) = pi * radius^2
    
    
    data Rectangle = Rectangle { height :: Double, width :: Double }
                   deriving Typeable
    
    instance Shape Rectangle where
      getArea (Rectangle height width) = height * width
    
    exampleData :: [Object Shape]
    exampleData = [Obj (Circle 1.5), Obj (Rectangle 2 3)]
    
    …但由于
    对象
    中的
    可键入
    约束,我们可以向下转换:如果我们正确猜测
    对象
    中包含的类型,我们可以恢复原始类型:

    -- | For each 'Shape' in the list, try to cast it to a Circle.  If we
    -- succeed, then pass the result to a monomorphic function that 
    -- demands a 'Circle'.  Evaluates to:
    --
    -- >>> example
    -- ["A Circle of radius 1.5","A Shape with area 6.0"]
    example :: [String]
    example = mapMaybe step exampleData
      where step shape = describeCircle <$> (downcast shape)
                     <|> Just (describeShape shape)
    
    describeCircle :: Circle -> String
    describeCircle (Circle radius) = "A Circle of radius " ++ show radius
    
    describeShape :: Shape a => a -> String
    describeShape shape = "A Shape with area " ++ show (getArea shape)
    
    ——|对于列表中的每个“形状”,尝试将其转换为圆形。如果我们
    --成功,然后将结果传递给
    --需要一个“圆圈”。评估结果为:
    --
    -->>>示例
    --[“半径为1.5的圆”,“面积为6.0”的形状]
    示例::[String]
    示例=映射可能步骤示例数据
    其中阶梯形状=描述圆形(向下浇铸形状)
    只是(描述形状)
    描述圆::圆->字符串
    描述圆(圆半径)=“半径的圆”++显示半径
    描述形状::形状a=>a->字符串
    describeShape shape=“带区域的形状”++显示(getArea shape)
    
    data Circle = Circle { radius :: Double }
                deriving Typeable
    
    instance Shape Circle where
      getArea (Circle radius) = pi * radius^2
    
    
    data Rectangle = Rectangle { height :: Double, width :: Double }
                   deriving Typeable
    
    instance Shape Rectangle where
      getArea (Rectangle height width) = height * width
    
    exampleData :: [Object Shape]
    exampleData = [Obj (Circle 1.5), Obj (Rectangle 2 3)]
    
    -- | For each 'Shape' in the list, try to cast it to a Circle.  If we
    -- succeed, then pass the result to a monomorphic function that 
    -- demands a 'Circle'.  Evaluates to:
    --
    -- >>> example
    -- ["A Circle of radius 1.5","A Shape with area 6.0"]
    example :: [String]
    example = mapMaybe step exampleData
      where step shape = describeCircle <$> (downcast shape)
                     <|> Just (describeShape shape)
    
    describeCircle :: Circle -> String
    describeCircle (Circle radius) = "A Circle of radius " ++ show radius
    
    describeShape :: Shape a => a -> String
    describeShape shape = "A Shape with area " ++ show (getArea shape)