如何为Generic编写一个实例来派生一个像singleton :: a - >这样的函数f

时间:2018-04-10 21:43:17

标签: haskell

根据我之前收到的建议(How to write an instance for Generic to derive a function like zero::a (i.e. a constant)?)我成功添加了类似的函数,但是失败的函数转换了一个用类型包装的值中的单个值(例如singleton :: a - &gt ; [一个])。

我到目前为止:

class Single l   where
    mkOne :: x -> l    
    default mkOne :: (Generic l, Generic x, Single l, Gsingle (Rep l)) => x -> l  
    mkOne x = to ( gmkOne (from x))

class Gsingle l where 
    gmkOne :: x -> l x

instance Gsingle U1 where   -- this is for zero
  gmkOne x = U1

instance  (Gsingle a) => Gsingle (K1 i a) where
    gmkOne (K1 x) = K1 (mkOne x)

instance Single f => Gsingle (M1 i c f) where
  gmkOne (M1 x1) = M1 (gmkOne x1)

instance (Gsingle f, Gsingle h) => Gsingle (f :*: h) where
  gmkOne  (x1 :*: y1) = gmkOne x1:*: gmkOne y1

通过查看我不理解x中的Gsingle类型参数的示例,或者更确切地说如何处理Gsingle中的签名x -> lx,我的印象很明显。

我尝试使用类型系列:

class Single l   where
    type ST l 
    mkOne :: (ST l) -> l    
    default mkOne :: (Generic l, Generic (ST l), Single l, Gsingle (Rep l)) => (ST l) -> l  
    mkOne x = to ( gmkOne (from x))

class Gsingle l where 
    type STG l 
    gmkOne :: (STG l)  -> l x
instance Gsingle U1 where   -- this is for zero
  gmkOne x = U1

instance  (Gsingle a) => Gsingle (K1 i a) where
    gmkOne (K1 x) = K1 (mkOne x)

instance Single f => Gsingle (M1 i c f) where
  gmkOne (M1 x1) = M1 (gmkOne x1)

instance (Gsingle f, Gsingle h) => Gsingle (f :*: h) where
  gmkOne  (x1 :*: y1) = gmkOne x1:*: gmkOne y1

但实例Gsingle (M1 i c f)Gsingle (f :*: h)中的类型错误仍然存​​在。

1 个答案:

答案 0 :(得分:2)

这个类通常被称为“尖头”,可以表示为:

class Pointed f where
  point :: a -> f a
  default point :: (Generic1 f, Pointed (Rep1 f)) => a -> f a
  point = to1 . point

您只需要每个构造函数的实例:

instance Pointed c => Pointed (M1 i t c) where
  point = M1 . point

instance Monoid c => Pointed (K1 i c) where
  point _ = K1 mempty

instance Pointed U1 where
  point _ = U1

instance Pointed r => Pointed (l :+: r) where
  point = R1 . point

instance (Pointed l, Pointed r) => Pointed (l :*: r) where
  point x = point x :*: point x

instance Pointed Par1 where
  point = Par1

instance Pointed f => Pointed (Rec1 f) where
  point = Rec1 . point

instance (Pointed l, Pointed r) => Pointed (l :.: r) where
  point = Comp1 . point . point

然后它会正常工作:

data Three a = Three a a a deriving (Show,Generic1)

>>> point True :: Three Bool
Three True True True

instance Pointed []

>>> point True :: [Bool]
[True,True,True,True,True,True...

您可能会注意到pure类中与Applicative的相似性:GHC库邮件列表上实际上有a proposal,以便将此精确实例添加到上面的每个构造函数中。