我如何限制黑胶唱片/复合唱片?

How can I constrain Vinyl / Composite Records?

我有一个可扩展的Vinyl / Composite记录(类似于HList,Frames...),我想生成keys/values的元组,例如

tuplify '[String :-> Whatevs, ...] :: [(String, String)]

这出奇的难。 original gist.

Solution Gist, thanks to Alec below

type FA = "a" :-> String
type FB = "b" :-> Int
type AB = '[FA, FB]

ab :: Rec Identity AB
ab = "A" :*: 1 :*: RNil

tuplify :: (Show a) => Rec Identity '[a] -> [(String, String)]
tuplify = recordToList . rmap undefined -- ??????
-- tuplify ab = [("a", "A"), ("b", "1")]

如果您想尝试我到目前为止所做的事情,请查看 gist,它有经过深思熟虑的示例和我看到的错误:

这是Composite中refying的硬件(reifyDicts):

乙烯基也一样(reifyConstraints):

AFAICT,问题在于 rmap:

rmap :: (forall x. f x -> g x) -> Rec f rs -> Rec g rs

映射的 fn 已定义 forall x,但我的 tuplify 受到约束,我认为具体化应该将约束移动到类型中(这就是 Dict 的用途) ,但是,唉,到目前为止运气不好。

我无法在我的全局 Stack 设置中安装 composite 相关内容,但以下内容应该仍然有效(我只是复制粘贴了相关定义)。也就是说,我认为基于类型的简单 type-class 调度在这里更简单(因为约束是不平凡的)。启用所有正确的扩展 [1] 后,您只需要:

class Tuplify a where
  tuplify :: a -> [(String, String)]

instance Tuplify (Rec Identity '[]) where
  tuplify RNil = []

instance (Show t, KnownSymbol s, Tuplify (Rec Identity rs)) =>
           Tuplify (Rec Identity (s :-> t ': rs)) where
  tuplify (v :*: rs) = (symbolVal (Proxy :: Proxy s), show v) : tuplify rs

然后,在 GHCi 中:

ghci> tuplify ab
[("a","\"A\""),("b","1")]

如果您真的想尝试具体化约束方法,则必须首先为您想要的特定约束声明类型 class 和实例:

class ShowField a where 
  showField :: a -> (String, String)                                                                                

instance (KnownSymbol s, Show a) => ShowField (Identity (s :-> a)) where
  showField (Identity (Val v)) = (symbolVal (Proxy :: Proxy s), show v)

那么使用reifyConstraintsrmap就变得更直接了:

tuplify' :: RecAll Identity rs ShowField => Rec Identity rs -> [(String, String)]
tuplify' xs = recordToList
            . rmap (\(Vinyl.Compose (Dict x)) -> Vinyl.Const $ showField x)
            $ reifyConstraint (Proxy :: Proxy ShowField) xs

我想 reifyDicts 也可能有类似的东西,尽管我希望有一个使用 ValuesAllHave 而不是 AllHave 定义的变体(这样我们就可以绕过声明 ShowField 键入 class 并在一个函数中完成所有操作)。


[1] extensions needed for first example

{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE FlexibleInstances   #-}
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies        #-}
{-# LANGUAGE TypeOperators       #-}