为了在简单产品上泛化地派生FromRow
类类的实例,我想静态地分析一种类型,而不提供任何具体的术语。
示例:
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的时候,我还没有一个术语,因此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
来分析事物的结构和类型,即我们不关心实际值的地方?如果做不到这一点,它会覆盖这个用例吗?
发布于 2021-10-24 14:16:41
你不需要提供一个术语。您不需要Rep a
的值,只需要将其作为一个类型来检查,这可以不使用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)
https://stackoverflow.com/questions/69697360
复制相似问题