繁体   English   中英

与GHC的不匹配

[英]Kind mismatch with GHC.Generics

我正在尝试在Haskell中编写通用向量空间实现。 我的实现如下:

import qualified GHC.Generics as G
import GHC.Generics hiding (V1)

class GVecSpace v where
  addVs :: v -> v -> v
  scaleV :: Double -> v -> v

instance GVecSpace (G.V1 a) where
  addVs _ _ = undefined
  scaleV _ _ = undefined

instance GVecSpace (G.U1 a) where
  addVs _ x = x -- no value
  scaleV _ x = x -- no value

instance (GVecSpace (f a), GVecSpace (g a)) => GVecSpace ((f :+: g) a) where
  addVs (L1 x) (L1 y) = L1 $ addVs x y
  addVs (R1 x) (R1 y) = R1 $ addVs x y
  scaleV d (L1 x) = L1 $ scaleV d x
  scaleV d (R1 x) = R1 $ scaleV d x

instance (GVecSpace (f a), GVecSpace (g a)) => GVecSpace ((f :*: g) a) where
  addVs (x1 :*: x2) (y1 :*: y2) =
    addVs x1 y1 :*: addVs x2 y2
  scaleV d (x1 :*: x2) =
    scaleV d x1 :*: scaleV d x2

instance (GVecSpace c) => GVecSpace (K1 i c p) where
  addVs (K1 x) (K1 y) = K1 $ addVs x y
  scaleV d (K1 x) = K1 $ scaleV d x

instance (GVecSpace (f p)) => GVecSpace (M1 i c f p) where
  addVs (M1 x) (M1 y) = M1 $ addVs x y
  scaleV d (M1 x) = M1 $ scaleV d x

instance (Generic a, GVecSpace (Rep a)) => GVecSpace a where
  addVs x y =
    G.to $ addVs (G.from x) (G.from y)
  scaleV d x =
    G.to $ scaleV d (G.from x)

但是GHC抱怨是因为Rep a的类型错误:

Expecting one more argument to ‘Rep a’
The first argument of ‘GVecSpace’ should have kind ‘*’,
  but ‘Rep a’ has kind ‘* -> *’
In the instance declaration for ‘GVecSpace a’

为了使这项工作有效,我应该更改什么? 一种选择是使GVecSpace仅适用于* -> * ,但这似乎很尴尬。 有办法避免这种情况吗?

要创建一个使用GHC.Generics的库,我们首先需要满足一些先决条件。

{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}

import GHC.Generics as G

泛型的所有表示形式都带有一个称为“参数” p的额外类型参数。 您可以在Generic a类中以Rep a类型的类型看到此类型, type Rep a :: * -> * 数据类型的表示不仅仅是另一种数据类型,它是类型为* -> *的类型,与FunctorMonad相同。 它采用另一种类型作为参数。 大多数时候,基于通用表示为类定义实例时,我们只会忽略该参数。

由于有额外的参数,定义非泛型类很有用。 我们将在以后添加更多内容。

class VecSpace v where
    addVs :: v -> v -> v
    scaleV :: Double -> v -> v

    ...

该类的通用版本GVecSpace在所有值的类型上都有一个额外的参数a 以前使用v每个地方,都会使用fa 我们将通过在GVecSpace的名称前面加上g来为VecSpace

class GVecSpace f where
    gaddVs :: f a -> f a -> f a
    gscaleV :: Double -> f a -> f a

GVecSpace类有点尴尬,仅适用于* -> * ,但仅用于为VecSpace设置默认实现。 您将在其他任何地方使用VecSpace

只有一个构造函数的单元类型是向量空间。 请注意, G.U1不适用于参数。

instance GVecSpace G.U1 where
  gaddVs _ x = x -- no value
  gscaleV _ x = x -- no value

两个向量空间的乘积是一个向量空间。 请注意, fg以及f :*: g不适用于参数类型。

instance (GVecSpace f, GVecSpace g) => GVecSpace (f :*: g) where
  gaddVs (x1 :*: x2) (y1 :*: y2) =
    gaddVs x1 y1 :*: gaddVs x2 y2
  gscaleV d (x1 :*: x2) =
    gscaleV d x1 :*: gscaleV d x2

对于K1我们从类型中删除最终参数p ,并根据非通用VecSpace c参数仅具有kind * (普通类型),因此它不能是GVecSpace的实例。

instance (VecSpace c) => GVecSpace (K1 i c) where
  gaddVs (K1 x) (K1 y) = K1 $ addVs x y
  gscaleV d (K1 x) = K1 $ scaleV d x

对于M1元数据节点,我们从类型中删除最后一个参数p

instance (GVecSpace f) => GVecSpace (M1 i c f) where
  gaddVs (M1 x) (M1 y) = M1 $ gaddVs x y
  gscaleV d (M1 x) = M1 $ gscaleV d x

现在我们可以回到VecSpace类,并在默认的东西是一个怎么补VecSpace时,其表示有GVecSpace实例。 我们转换参数到表示from类型v ,执行上表示操作的通用版本,然后再转换回to类型v时,我们就大功告成了。

class VecSpace v where
    addVs :: v -> v -> v
    scaleV :: Double -> v -> v

    default addVs :: (Generic v, GVecSpace (Rep v)) => v -> v -> v
    addVs x y = to (gaddVs (from x) (from y))

    default scaleV :: (Generic v, GVecSpace (Rep v)) => Double -> v -> v
    scaleV s = to . gscaleV s . from

采用

假设您已经观察到Double形成向量空间

instance VecSpace Double where
    addVs = (+)
    scaleV = (*)

我们可以得出一个工作VecSpace中的条款比如元组default为s VecSpace

instance (VecSpace a, VecSpace b) => VecSpace (a, b)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM