Haskell 用数据族替换单例数据类型

Haskell 用数据族替换单例数据类型,haskell,dependent-type,type-families,Haskell,Dependent Type,Type Families,因此,在我当前的项目中,我发现自己正在使用单例类型进行一系列类型级逻辑 例如: {-# LANGUAGE DataKinds #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE GADTs #-} module TypeBools where type family (||) (a :: Bool) (b :: Bool) ::

因此,在我当前的项目中,我发现自己正在使用单例类型进行一系列类型级逻辑

例如:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GADTs #-}
module TypeBools where

type family (||) (a :: Bool) (b :: Bool) :: Bool where
  'False  || 'False = 'False
  'False  || 'True  = 'True
  'True   || 'False = 'True
  'True   || 'True  = 'True

data OrProof (a :: Bool) (b :: Bool) (c :: Bool) where
  OrProof :: SBool (a || b) -> OrProof a b (a || b)

data SBool (b :: Bool) where
  SFalse  :: SBool 'False
  STrue   :: SBool 'True

class Boolean b where
  sBool :: SBool b
instance Boolean 'False where
  sBool = SFalse
instance Boolean 'True where
  sBool = STrue

orProof :: (Boolean a, Boolean b) => OrProof a b (a || b)
orProof = go sBool sBool where

  go :: SBool a -> SBool b -> OrProof a b (a || b)
  go SFalse SFalse = OrProof SFalse
  go SFalse STrue = OrProof STrue
  go STrue SFalse = OrProof STrue
  go STrue STrue = OrProof STrue
这对我来说很有效。我喜欢不必在街上兜圈子 单例类型手动,能够在必要时通过typeclass调用它们 e、 上面的布尔类,但这导致了一系列相当类似的 仅用于将类型具体化为单例数据的类型类

我想也许我可以把多个类型类抽象成一个类型族, 例如,将上面的SBool和Boolean替换为:

{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ConstraintKinds #-}
-- ...
class Singleton (t :: k) where
  data Sing t
  sing :: Sing t

instance Singleton 'False where
  data Sing 'False = SFalse
  sing = SFalse

instance Singleton 'True where
  data Sing 'True = STrue
  sing = STrue

type SBool b = Sing (b :: Bool)

type Boolean b = Singleton (b :: Bool)
sBool :: Boolean b => SBool b
sBool = sing
但是我得到了模式匹配错误:

TypeBools2.hs:42:13:
    Couldn't match type ‘b1’ with ‘'True’
      ‘b1’ is a rigid type variable bound by
           the type signature for
             go :: SBool a1 -> SBool b1 -> OrProof a1 b1 (a1 || b1)
           at TypeBools2.hs:40:9
    Expected type: SBool b1
      Actual type: Sing 'True
    Relevant bindings include
      go :: SBool a1 -> SBool b1 -> OrProof a1 b1 (a1 || b1)
        (bound at TypeBools2.hs:41:3)
    In the pattern: STrue
    In an equation for ‘go’: go SFalse STrue = OrProof STrue
    In an equation for ‘orProof’:
        orProof
          = go sBool sBool
          where
              go :: SBool a -> SBool b -> OrProof a b (a || b)
              go SFalse SFalse = OrProof SFalse
              go SFalse STrue = OrProof STrue
              go STrue SFalse = OrProof STrue
              go STrue STrue = OrProof STrue
我不确定是否还有其他东西可以说服编译器
b1应该有一个好样的布尔,或者如果我只是在这里找错了树。

你要求的功能和更多功能可以在中找到。很长一段时间以来,它一直是类型级编程的最终模板。您应该使用它或复制实现。无论如何,我会在这里做一个简单的单例解决方案展示

模式匹配不起作用,因为STrue和SFalse位于不同的数据定义中,而这些数据定义一开始就不是GADT。模式匹配仅在正确的GADT-s上完成时细化类型。我们需要对种类进行分派,以便能够将同一种类的所有单例构造函数组合在一起

我们可以使用适当的类或顶级数据族来实现这一点。对于我们现在的目的来说,后者更简单,所以让我们这样做:

data family Sing (x :: k)

data instance Sing (b :: Bool) where
  STrue :: Sing True
  SFalse :: Sing False
对于sing,我们不需要进行实物分派,因为我们只使用它来获取特定的提升值,因此以下方法有效:

class SingI (x :: k) where
   sing :: Sing x

instance SingI True  where sing = STrue
instance SingI False where sing = SFalse
至于orporoof,我们想要的是类型级别| |的单例,它最直接地通过以下类型完成:Sing b1->Sing b2->Sing b1 | | b2。我们将根据象形文字单件命名惯例,将其命名为%:| |

type family (:||) (b1 :: Bool) (b2 :: Bool) :: Bool where
  True  :|| b = True
  False :|| b = b

(%:||) :: Sing b1 -> Sing b2 -> Sing (b1 :|| b2)
(%:||) STrue  b2 = STrue
(%:||) SFalse b2 = b2
OrProof并不是很有用,因为它只是一种特殊的等式类型以及SingI约束或简单的SingC:


您所要求的功能和更多功能可以在中找到。很长一段时间以来,它一直是类型级编程的最终模板。您应该使用它或复制实现。无论如何,我会在这里做一个简单的单例解决方案展示

模式匹配不起作用,因为STrue和SFalse位于不同的数据定义中,而这些数据定义一开始就不是GADT。模式匹配仅在正确的GADT-s上完成时细化类型。我们需要对种类进行分派,以便能够将同一种类的所有单例构造函数组合在一起

我们可以使用适当的类或顶级数据族来实现这一点。对于我们现在的目的来说,后者更简单,所以让我们这样做:

data family Sing (x :: k)

data instance Sing (b :: Bool) where
  STrue :: Sing True
  SFalse :: Sing False
对于sing,我们不需要进行实物分派,因为我们只使用它来获取特定的提升值,因此以下方法有效:

class SingI (x :: k) where
   sing :: Sing x

instance SingI True  where sing = STrue
instance SingI False where sing = SFalse
至于orporoof,我们想要的是类型级别| |的单例,它最直接地通过以下类型完成:Sing b1->Sing b2->Sing b1 | | b2。我们将根据象形文字单件命名惯例,将其命名为%:| |

type family (:||) (b1 :: Bool) (b2 :: Bool) :: Bool where
  True  :|| b = True
  False :|| b = b

(%:||) :: Sing b1 -> Sing b2 -> Sing (b1 :|| b2)
(%:||) STrue  b2 = STrue
(%:||) SFalse b2 = b2
OrProof并不是很有用,因为它只是一种特殊的等式类型以及SingI约束或简单的SingC:


我可以问一下你的| |为什么不短路吗?我希望使用'False | | x=x;'可以得到更好的减少例如,True | | x='True。你应该直接使用它,但如果你不打算使用它,你应该看看它们是如何做的,并复制它,因为它们正是你想要的。特别是,您需要一个非关联的数据族数据族Sing t::k;类Singleton t::k where sing::sing t和数据实例sing b::Bool where…dfeuer:它可以。不过,这是问题的另一个方面。而且,我很难理解你的orporite和orporite应该表达什么。他们似乎有点。。。迂回的我知道这与你的问题没有直接关系。德弗尔:这是一个问题的简化示例,但它允许你进行类型级逻辑,而不用担心GHC pre8无法通过围绕参数进行推理来推断内射性。例如,or::Boolean a,Boolean b=>SBool a | | b;or=case或orProof of orProof c->c给出了旧的NB:“| |”是一个类型函数,可能不是内射模糊错误。请问为什么您的| |没有短路?我希望使用'False | | x=x;'可以得到更好的减少例如,True | | x='True。你应该直接使用它,但如果你不打算使用它,你应该看看它们是如何做的,并复制它,因为它们正是你想要的。特别是,您需要一个非关联的数据族数据族Sing t::k;类Singleton t::k where sing::sing t和数据实例sing b::Bool where…dfeuer:它可以。不过,这是问题的另一个方面。而且,我很难理解你的orporite和orporite应该表达什么。看起来有点像。
.. 迂回的我知道这与你的问题没有直接关系。德弗尔:这是一个问题的简化示例,但它允许你进行类型级逻辑,而不用担心GHC pre8无法通过围绕参数进行推理来推断内射性。例如,or::Boolean a,Boolean b=>SBool a | | b;or=case orProof of orProof c->c给出了旧的NB:“| |”是一个类型函数,可能不是内射模糊错误。Singleton几乎拥有当前GHC中所有人类可能的功能。这并不简单,所以如果您有问题,请随时提出进一步的问题。我在这个网站上也有很多关于单身汉的答案,你可能会想知道。单身汉几乎拥有当前GHC所能提供的一切。这并不简单,所以如果您有问题,请随时提出进一步的问题。我在这个网站上也有一些与单身相关的答案,你可能会想知道。