使用GHC泛型定义“空"样功能? [英] Defining an "mempty"-like function with GHC Generics?

查看:54
本文介绍了使用GHC泛型定义“空"样功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为Zoho REST API编写一个客户端库,并且有一堆不同的记录类型,这些记录类型具有所有也许是字段,即:

I am writing a client library for the Zoho REST API and have a bunch of different record types that have all Maybe a fields, i.e:

data Approval = Approval
  { apDelegate :: Maybe Bool
  , apApprove :: Maybe Bool
  , apReject :: Maybe Bool
  , apResubmit :: Maybe Bool
  } deriving (Eq, Show, Generic)

data ContactSpecialFields = ContactSpecialFields
  { csfCurrencySymbol :: Maybe Text -- $currency_symbol
  , csfState :: Maybe Text -- $state
  , csfProcessFlow :: Maybe Bool -- $process_flow
  , csfApproved :: Maybe Bool -- $approved
  , csfApproval :: Approval  -- $approval
  , csfEditable :: Maybe Bool -- $editable
  } deriving (Eq, Show)

-- and so on

我需要一种定义此类空"记录的方法,例如:

I need an way to define "empty" records of such types, eg:

emptyApproval :: Approval
emptyApproval = Approval
  { apDelegate = Nothing
  , apApprove = Nothing
  , apReject = Nothing
  , apResubmit = Nothing
  }

因此,我联系了 GHC.Generics ,并得到了一些有用的信息(这是越野车!):

Therefore, I reached out for GHC.Generics and got something working (which is buggy!):

-- These parts seem logically correct to me...

class GEmptyZohoStructure f where
  gEmptyZohoStructure :: f p

instance (GEmptyZohoStructure f, GEmptyZohoStructure g) => GEmptyZohoStructure (f :*: g) where
  gEmptyZohoStructure = (gEmptyZohoStructure :: f p) :*: (gEmptyZohoStructure :: g p)

instance GEmptyZohoStructure Maybe where
  gEmptyZohoStructure = Nothing

class EmptyZohoStructure a where
  emptyZohoStructure :: a

  default emptyZohoStructure :: (Generic a, (GEmptyZohoStructure (Rep a))) => a
  emptyZohoStructure = GHC.Generics.to gEmptyZohoStructure

-- Whereas these parts are random type-class instances that I've written, just 
-- to get the code to compile.

instance (GEmptyZohoStructure f) => GEmptyZohoStructure (M1 i t f) where
  gEmptyZohoStructure = (gEmptyZohoStructure :: f p)

instance (GEmptyZohoStructure f) => GEmptyZohoStructure (K1 i (f p)) where
  gEmptyZohoStructure = gEmptyZohoStructure

instance EmptyZohoStructure Approval

在编译代码时,以下(可理解的)结果会在运行时导致堆栈溢出:

while the code compiles, the following (understandably) results in a stack overflow during runtime:

ghci> emptyZohoStructure  :: Approval
*** Exception: stack overflow

我一直在

I was following the encode tutorial given at https://www.stackage.org/haddock/lts-12.1/base-4.11.1.0/GHC-Generics.html#g:12 , where due to the argument being passed to the encode function, it allows one the opportunity to unwrap the M1 / K1 constructor and build some meaningful recursion hierarchy. How do I write generic for M1 and K1 for my use-case (where the generic function doesn't really have any arguments)?

推荐答案

在泛型类型类中定义 GEmptyZohoStructure Maybe 毫无意义.

There is no point defining GEmptyZohoStructure Maybe in a typeclass for generics.

class G f where 
  gempty' :: f p
instance (G f, G g) => G ( f :*: g) where 
  gempty' = gempty' :*: gempty'

instance G c => G (D1 x c) where
  gempty' = M1 gempty'
instance G s => G (C1 x s) where
  gempty' = M1 gempty'    
instance E t => G (S1 m (Rec0 t)) where -- the key instance
  gempty' = M1 (K1 gempty)

class E a where
  gempty :: a
  default gempty :: (Generic a, G (Rep a)) => a
  gempty = to gempty'    
instance E (Maybe a) where 
  gempty = Nothing

之后,您可以定义由Maybe值组成的任何产品类型.

After that you can define any product type consisting of Maybe values.

这篇关于使用GHC泛型定义“空"样功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆