简体   繁体   English

使用泛型静态分析类型

[英]Statically analyze type with Generics

For the purpose of generically deriving instances for FromRow -kind-of-class on simple products I would like to statically analyze a type without actually providing any concrete terms.为了在简单产品上为FromRow类一般派生实例,我想静态分析一个类型,而不实际提供任何具体术语。

Example:例子:

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)

The "trick" is I need the rowrep before I fetch any data - to possibly override the defaults for some or even all columns. “技巧”是我在获取任何数据之前需要 rowrep - 可能会覆盖某些甚至所有列的默认值。 At the point in time where I want to use rowrep I don't yet have a term, thus the Proxy .在我想使用 rowrep 的时间点我还没有一个术语,因此Proxy Writing instances of FromRow could get extremely tedious and error prone so I thought I'd add a default implementation for Generic types.编写FromRow实例可能会变得非常乏味且容易出错,所以我想我会为Generic类型添加一个default实现。 However, it seems to get the generic representation I need to provide a term of a given type ( from :: a -> Rep a ), knowledge of type itself is not enough.然而,它似乎得到了我需要提供给定类型的术语( from :: a -> Rep a )的通用表示,类型本身的知识是不够的。

Indeed we can see this isn't just a gimmick of the API and that Generic representations do hold values:事实上,我们可以看到这不仅仅是 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}})}}

Is there a way to use Generic just to analyze the structure and type of things ie where we don't care about actual values?有没有一种方法可以使用Generic来分析事物的结构和类型,即我们不关心实际值的地方? Failing that, is TH going to cover this use case?如果做不到这一点,TH 会涵盖这个用例吗?

You don't need to provide a term.您无需提供术语。 You don't need a value of Rep a , you just need to inspect this as a type , and that can be done without ever using from .您不需要Rep a的值,您只需要将其作为type进行检查,并且无需使用from即可完成此操作。

For that matter, you also don't need Proxy , that was always just an ugly hack to make up for a deficiency of Haskell before TypeApplications came along.就此而言,你也不需要Proxy ,在TypeApplications出现之前,这总是一个丑陋的黑客来弥补 Haskell 的不足。

{-# LANGUAGE TypeFamilies, TypeApplications, AllowAmbiguousTypes
           , ScopedTypeVariables, UnicodeSyntax, DefaultSignatures #-}

data NativeType = Intish | Floatish

class FromRow a where
  rowrep :: [Maybe NativeType]

instance FromRow Int where
  rowrep = [Just Intish]

Now, for writing generic instances we first need a helper class that does the type-level inspection of the Rep :现在,为了编写通用实例,我们首先需要一个辅助类来对Rep进行类型级别的检查:

class GFromRow g 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

Then the default implementation will be那么默认的实现将是

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM