【问题标题】:Using Generic Deriving with a Record Haskell使用记录 Haskell 的泛型派生
【发布时间】:2013-07-02 02:38:49
【问题描述】:

我基本上是想看看我是否可以在 Haskell 中模拟 ORM 框架,这样如果用户想要制作数据库模型,他们会做这样的事情

data Car = Car {
        company :: String, 
        model :: String, 
        year :: Int
        } deriving (Model)

表格是“汽车”,列是公司、型号、年份

要在 Haskell 中执行此操作,您必须结合使用类和泛型,这就是我遇到的问题。使用本教程 (http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/generic-programming.html),我想出了这个(基本上是复制和重命名,所以我可以让代码正常工作)

{-# LANGUAGE DeriveGeneric, TypeOperators, TypeSynonymInstances, FlexibleInstances #-}

module Main where
import GHC.Generics

class SModel b where
        s_new :: b -> IO()

instance SModel Int where
        s_new s = putStrLn s++":Int"

instance SModel Integer where
        s_new s = putStrLn s++":Integer"

instance SModel String where
        s_new s = putStrLn s++":String"    

class Model m where
        new :: m a -> IO()

instance Model U1 where
        new U1 = putStrLn "unit"

instance (Model a, Model b) => Model (a :*: b) where
        new (a :*: b) = do
                new a
                new b

instance (Model a, Model b) => Model (a :+: b) where
        new (L1 x) = new x
        new (R1 x) = new x

instance (Model a) => Model (M1 i c a) where
        new (M1 x) = new x

instance (SModel a) => Model (K1 i a) where
        new (K1 x) = s_new x

data Car = Car {
        company :: String, 
        model :: String, 
        year :: Int
        } deriving (Model)

以上代码会报错

Cannot derive well-kinded instance of form `Model (Car ...)'
      Class `Model' expects an argument of kind `* -> *'
    In the data declaration for `Car'

我有点卡在这一点上,我相信我已经实例化了所有必需的泛型类型来覆盖记录

【问题讨论】:

  • 您不能在派生子句中使用Model。相反,您应该派生Generic,然后为SModel 提供默认实例。请参阅“通用默认值”的 GHC 用户指南。 github.com/kosmikus/generic-deriving/blob/master/src/Generics/… 上还有一些初步改进的文档
  • 所以 Haskell 没有官方支持使用 deriving 除了 show、eq(以及其他一些内置的衍生工具)

标签: generics haskell record deriving


【解决方案1】:

正如kosmikus 在他的评论中所说,你不能直接推导出Model。首先,您需要一个为Model 提供通用默认值的“前端”类,如下所示:

class FModel a where
    fnew :: a -> IO()

    default new :: (Generic a, Model (Rep a)) => a -> IO()
    fnew = new . from

那么你可以这样做:

Car = ... deriving Generic
instance FModel Car

你有想要的实例。

【讨论】:

  • 如果样板文件太多(如果你有更多要“派生”的类,它会得到更多),你可以使用 TemplateHaskell 生成所有空实例,尽管如果我不会这样做你只有一门课。
猜你喜欢
  • 2014-03-22
  • 1970-01-01
  • 2019-04-15
  • 2013-09-09
  • 2012-09-08
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多