数据类型 - 通用编程和神秘的gdmXXX

时间:2014-09-09 16:05:08

标签: haskell generic-programming

我对名为Generic的类使用数据类型泛型编程,该类包含一个名为get的方法。如果我的最终用户定义了类型并忘记添加deriving Generic,并调用put,他们会看到如下错误消息:

No instance for (ALife.Creatur.Genetics.Code.BRGCWord8.GGene
(GHC.Generics.Rep ClassifierGene))
arising from a use of `ALife.Creatur.Genetics.Code.BRGCWord8.$gdmput'

我可以告诉用户如何修复错误,但我对此$gdmput感到好奇。我认为它是一个自动生成的功能或符号,但是通过什么?是使用DefaultSignatures编译指示还是DeriveGeneric编译指示?我读了一些关于数据类型 - 泛型编程的论文,但没有看到任何对gdmXXX符号的引用。

这里是Generic类的定义。

{-# LANGUAGE TypeFamilies, FlexibleContexts, FlexibleInstances,
    DefaultSignatures, DeriveGeneric, TypeOperators #-}
. . .

-- | A class representing anything which is represented in, and
--   determined by, an agent's genome.
--   This might include traits, parameters, "organs" (components of
--   agents), or even entire agents.
--   Instances of this class can be thought of as genes, i.e.,
--   instructions for building an agent.
class Genetic g where
  -- | Writes a gene to a sequence.
  put :: g -> Writer ()

  default put :: (Generic g, GGenetic (Rep g)) => g -> Writer ()
  put = gput . from

  -- | Reads the next gene in a sequence.
  get :: Reader (Either [String] g)

  default get :: (Generic g, GGenetic (Rep g)) => Reader (Either [String] g)
  get = do
    a <- gget
    return $ fmap to a

  getWithDefault :: g -> Reader g
  getWithDefault d = fmap (fromEither d) get

class GGenetic f where
  gput :: f a -> Writer ()
  gget :: Reader (Either [String] (f a))

-- | Unit: used for constructors without arguments
instance GGenetic U1 where
  gput U1 = return ()
  gget = return (Right U1)

-- | Constants, additional parameters and recursion of kind *
instance (GGenetic a, GGenetic b) => GGenetic (a :*: b) where
  gput (a :*: b) = gput a >> gput b
  gget = do
    a <- gget
    b <- gget
    return $ (:*:) <$> a <*> b

-- | Meta-information (constructor names, etc.)
instance (GGenetic a, GGenetic b) => GGenetic (a :+: b) where
  gput (L1 x) = putRawWord16 0 >> gput x
  gput (R1 x) = putRawWord16 1 >> gput x
  gget = do
    a <- getRawWord16
    case a of
      Right x -> do
        if even x -- Only care about the last bit
          then fmap (fmap L1) gget
          else fmap (fmap R1) gget
      Left s -> return $ Left s

-- | Sums: encode choice between constructors
instance (GGenetic a) => GGenetic (M1 i c a) where
  gput (M1 x) = gput x
  gget = fmap (fmap M1) gget

-- | Products: encode multiple arguments to constructors
instance (Genetic a) => GGenetic (K1 i a) where
  gput (K1 x) = put x
  gget = do
    a <- get
    return $ fmap K1 a

1 个答案:

答案 0 :(得分:6)

$gdm来自DefaultSignatures。这是一个产生类似错误消息的最小示例

{-# LANGUAGE DefaultSignatures #-}

data NoInstances = NoInstances

class Display a where
    display :: a -> String

    default display :: Show a => a -> String
    display = show

instance Display NoInstances

产生的错误消息是

defaultsignatures.hs:11:10:
    No instance for (Show NoInstances)
      arising from a use of `Main.$gdmdisplay'
    In the expression: Main.$gdmdisplay
    In an equation for `display': display = Main.$gdmdisplay
    In the instance declaration for `Display NoInstances'