2

我希望能够写出类似的东西:

reify (Proxy @True)) == True;
reify (Proxy @(Just 5)) == Just 5;

是否可以通过一揽子实施?我做到了

class Reify (a :: k) where
  reify :: Proxy a -> k

而且我不知道如何写这个,除了手工编写每个实例:一个实例为真,一个实例为假,等等。我不想全部手写,也不想使用模板haskell 为我做这件事。我可以只有一个实例来做吗?

或者也许存在其他一些方法?我的用例是能够编写:

type DeriveHelper :: Settings -> Type -> Type
newtype DeriveHelper s a = DeriveHelper a

instance (Generic a, GMyClass (Rep a)) => MyClass (DeriveHelper s a) where
  myMethod (DeriveHelper x) = genericMyMethod (reify (Proxy @s)) $ from x

-- and then
data FooBar ...
  deriving MyClass via DeriveHelper SomeSettings FooBar

至于我在世界上看到的这样做的图书馆,它们似乎都有一些小的设置,我相信这些设置都是手工实现的。

4

1 回答 1

4

如果我没有注意到目前最好的解决方案仍然是singletons包,我会失职,它提供了demote做你想做的事情的功能(见最后的例子)。但是,该实现在内部使用 Template Haskell 来提升现有Prelude类型,并要求您显式使用 TH 来提升其他类型。而且,你说你不想那样做...

所以,我想在技术上使用泛型是可行的。您可以使用Data.Typeableor来破坏kind的Type.Reflection类型级别,然后使用(或或其他)构造一个类型的术语。tk t kGHC.GenericsData.Data

Data.Typeable考虑以下用于类型破坏和Data.Data术语构造的概念证明:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Reify where

import Data.Typeable
import Data.Data

demote :: forall k t. (Typeable t, Data k) => Proxy (t :: k) -> k
demote pxy
  = let rep = typeRep pxy
    in  fromConstr $ mkConstr (dataTypeOf @k undefined)
                              (removeTick $ tyConName . typeRepTyCon $ rep)
                              []
                              Prefix
  where removeTick ('\'':xs) = xs

这只是部分实现,但它会降级任意空值前缀构造函数:

data MyType = A | B Int deriving (Show, Data)

main = do
    print $ (demote (Proxy @'Nothing) :: Maybe Int)
    print $ (demote (Proxy @'False) :: Bool)
    print $ (demote (Proxy @'A) :: MyType)

Int#我认为将其推广到处理任意数量的构造函数并添加对等的支持没有任何技术障碍。

也许有人在某个地方的包中实现了这个,但我不知道在哪里。

无论如何,singletons使用 TH 的解决方案已准备好运行,看起来像:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

module Reify where

import Data.Singletons
import Data.Singletons.TH
import Data.Kind
import GHC.Generics
import GHC.Natural

-- define a new type supporting "demote"
$(singletons [d|
  data MyType = A | B Bool deriving (Show)
  |])

-- add "demote" support to an existing type (e.g., imported from a library)
data LibraryType = C | D Bool deriving (Show)
$(genSingletons [''LibraryType])

main = do
  print $ (demote @('Just 5) :: Maybe Natural)
  print $ (demote @'False :: Bool)
  print $ (demote @'A :: MyType)
  print $ (demote @('D 'False) :: LibraryType)
于 2022-02-23T18:51:48.927 回答