使用`generics-sop`在编译时获取类型元数据信息

huangapple go评论65阅读模式
英文:

Using `generics-sop` to get type metadata info at compile time

问题

我迄今为止一直很成功地使用 `generics-sop`,但有一个用例,我想要获取记录字段的名称。

我正在处理的类型是乘积类型,我可以使用约束 `IsProductType a xs` 来强制执行这一点。

这样做,我最终会得到一堆类似以下的代码:

```haskell
import qualified Generics.SOP as SOP
import Generics.SOP (...)

f :: forall a xs. IsProductType a xs => ...
f = ... where
  datatypeInfo :: DatatypeInfo (SOP.Code a)
  datatypeInfo = SOP.datatypeInfo (Proxy :: Proxy a)
  constructorsInfo :: NP ConstructorInfo (Code a)
  constructorsInfo = SOP.constructorInfo datatypeInfo
  constructorInfo :: ConstructorInfo xs
  -- This is safe due to the (IsProductType a xs) constraint, as there is only one constructor
  constructorInfo = hd constructorsInfo 
  fieldsInfo :: NP FieldInfo xs
  fieldsInfo = let Record _ fields = y in fields

但在最后一行,我收到一个关于 Record 匹配不完整的警告。实际上,并非如此,ConstructorInfo 实际上有三个构造函数,而 Record 只匹配其中一个。

然后我意识到,我的代码可能会针对任何乘积类型编译,即使它们不是记录格式。我宁愿不要有不完整的匹配,但如果我能在 a 上放置一个约束,确保它是记录,那么不完整的匹配将永远不会在运行时失败,我会接受它。

我认为问题在于函数 datatypeInfo

datatypeInfo :: proxy a -> DatatypeInfo (Code a)

移除了类型级别的信息,因为 Code a,作为类型级别的列表列表,不再具有关于 a 是否具有命名记录字段的信息。

是否有其他使用 generics-sop 的方法来保留该信息?我非常喜欢 generics-sop,尤其是不必处理二叉树的总和/乘积组合,只需处理这个,所以如果 generics-sop 在编译时和运行时都暴露字段是否命名的信息,那将是很好的。


<details>
<summary>英文:</summary>

I&#39;ve been using `generics-sop` quite successfully so far, but for one use case I&#39;d like to get the names of record fields.

The types I&#39;m working with are product types, and I can use the constraint `IsProductType a xs` to enforce this.

Doing so I end up with a bunch of code like the following:

import qualified Generics.SOP as SOP
import Generics.SOP (...)

f :: forall a xs. IsProductType a xs => ...
f = ... where
datatypeInfo :: DatatypeInfo (SOP.Code a)
datatypeInfo = SOP.datatypeInfo (Proxy :: Proxy a)
constructorsInfo :: NP ConstructorInfo (Code a)
constructorsInfo = SOP.constructorInfo datatypeInfo
constructorInfo :: ConstructorInfo xs
-- This is safe due to the (IsProductType a xs) constraint, as there is only one constructor
constructorInfo = hd constructorsInfo
fieldsInfo :: NP FieldInfo xs
fieldsInfo = let Record _ fields = y in fields


But at the last line I get a warning about the `Record` match not being exhaustive. And it isn&#39;t, `ConstructorInfo` actually has three constructors, and `Record` is only matching one of them. 

So then I realised that my code probably will compile against any product type, even those not in record format. I&#39;d rather not have the incomplete match, but I&#39;d be okay with it if I could somehow put a constraint on `a` that ensured that it was a record, so the incomplete match will never fail at runtime. 

I think the issue is that the function [datatypeInfo](https://hackage.haskell.org/package/generics-sop-0.5.1.2/docs/Generics-SOP.html#v:datatypeInfo):

datatypeInfo :: proxy a -> DatatypeInfo (Code a)


Removes type level information, because `Code a`, being a type level list of lists, no longer has the information about whether `a` has named record fields or not.

Is there something else I can do using `generics-sop` to retain that information. I quite like `generic-sop`, in particular not having to deal with binary trees of sum/product combinations but just dealing with this, so it would be nice if `generics-sop` exposed the information about whether a field was named or not at compile time as well as runtime.



</details>


# 答案1
**得分**: 1

回答我自己的问题,我认为[records-sop][1]解决了这个问题。

  [1]: https://hackage.haskell.org/package/records-sop-0.1.1.0

<details>
<summary>英文:</summary>

Answering my own question, I think [records-sop][1] solves this issue. 

  [1]: https://hackage.haskell.org/package/records-sop-0.1.1.0

</details>



huangapple
  • 本文由 发表于 2023年3月12日 17:55:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/75712337.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定