【问题标题】:Statically analyze type with Generics使用泛型静态分析类型
【发布时间】:2021-10-24 13:45:19
【问题描述】:

为了在简单产品上一般派生FromRow-kind-of-class 的实例,我想静态分析一个类型而不实际提供任何具体术语。

例子:

class FromRow a where
  rowrep :: Proxy a -> [Maybe NativeType]
  fromRow :: Statement -> IO a

data User = User
  { name :: String
  , uid :: Int
  , active :: Bool
  } deriving (Show, Generic)

“诀窍”是我在获取任何数据之前需要 rowrep - 可能会覆盖某些甚至所有列的默认值。在我想使用 rowrep 的时间点上,我还没有一个术语,因此是 Proxy。编写FromRow 的实例可能会变得非常乏味且容易出错,所以我想我应该为Generic 类型添加一个default 实现。但是,它似乎获得了我需要提供给定类型的术语(from :: a -> Rep a)的通用表示,类型本身的知识是不够的。

确实,我们可以看到这不仅仅是 API 的噱头,通用表示确实具有价值:

> from (User "foo" 1 True)
M1 {unM1 = M1 {unM1 = M1 {unM1 = K1 {unK1 = "foo"}} :*: (M1 {unM1 = K1 {unK1 = 1}} :*: M1 {unM1 = K1 {unK1 = True}})}}

有没有办法使用Generic 来分析事物的结构和类型,即我们不关心实际值的地方?如果做不到这一点,TH 会涵盖这个用例吗?

【问题讨论】:

    标签: haskell ghc-generics


    【解决方案1】:

    您无需提供术语。您不需要 Rep a 的值,只需将其作为 type 进行检查,而无需使用 from 即可完成。

    就此而言,您也不需要Proxy,在TypeApplications 出现之前,这始终只是弥补Haskell 不足的丑陋黑客。

    {-# LANGUAGE TypeFamilies, TypeApplications, AllowAmbiguousTypes
               , ScopedTypeVariables, UnicodeSyntax, DefaultSignatures #-}
    
    import Data.Kind (Type)
    
    data NativeType = Intish | Floatish
    
    class FromRow a where
      rowrep :: [Maybe NativeType]
    
    instance FromRow Int where
      rowrep = [Just Intish]
    

    现在,为了编写通用实例,我们首先需要一个辅助类来对 Rep 进行类型级别检查:

    class GFromRow (g :: k -> Type) where
      gRowrep :: [Maybe NativeType]
    
    instance ∀ i c f . GFromRow f => GFromRow (M1 i c f) where
      gRowRep = gRowRep @f
    instance ∀ i c . FromRow c => GFromRow (K1 i c) where
      gRowRep = rowRep @c
    ...  -- instances for U1 and f:*:g
    

    那么默认实现将是

    class FromRow a where
      rowrep :: [Maybe NativeType]
      default rowrep :: GFromRow (Rep a) => [Maybe NativeType]
      rowrep = gRowrep @(Rep a)
    

    【讨论】:

    • 谢谢!出于某种原因,不得不为 GFromRow 添加一个亲切的签名,并在默认实现中为 gRowrep 添加一个注释,但在其他方面就像一个魅力:)
    • @user2847643,如果您出于某种原因不想想要使用类型应用程序,“传统”方法是通过编写Proxy :: Proxy a 或其他方式获取代理,仍在使用ScopedTypeVariables,除非您致力于让自己变得困难。
    猜你喜欢
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    • 2015-03-09
    相关资源
    最近更新 更多