使用记录Haskell进行通用派生 [英] Using Generic Deriving with a Record Haskell

查看:154
本文介绍了使用记录Haskell进行通用派生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我基本上试图看看我是否可以在Haskell中模拟一个ORM框架,这样如果用户想创建一个数据库模型,他们会这样做。

  data Car = Car {
company :: String,
model :: String,$ b $ year :: Int
}派生(Model )

如果表格是Car,列将是公司,模型,年份

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

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

模块Main其中
import GHC.Generics

class SModel b其中
s_new :: b - > IO()

实例SModel Int其中
s_new s = putStrLn s ++:Int

实例SModel整数其中
s_new s = putStrLn s ++ :整数

实例SModel字符串其中
s_new s = putStrLn s ++:String

class模型m其中
new :: ma - > ; IO()

实例模型U1其中
新U1 = putStrLn单元

实例(模型a,模型b)=>模型(a:*:b)其中
新(a:*:b)= do
新a
新b

实例(模型a,模型b )=>模型(a:+:b)其中
new(L1 x)= new x
new(R1 x)= new x

instance(Model a)=>模型(M1 i c a)其中
new(M1 x)= new x

instance(SModel a)=>模型(K1 ia)其中
new(K1 x)= s_new x

data Car = Car {
company :: String,
model :: String,
year :: Int
}派生(模型)

上述代码将生成错误

 无法派生形式为`Model(Car ...)'的良好主观实例
Class`Model '期待类似的论点`* - > *'
在`Car'的数据声明中

而且我有点卡住这一点,我相信我已经实例化了所有必需的泛型类型来覆盖记录 解决方案

As kosmikus 在他的评论中说,你不能直接派生 Model 。首先,您需要一个用于 Model 的'前端'类,以提供一个通用的默认类型,如下所示:

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

default new ::(Generic a,Model(Rep a))=> a - > IO()
fnew = new。从

然后你可以这样做:

  Car = ...推导泛型
实例FModel Car

并且您拥有所需的实例。


I am basically attempting to see if I can emulate an ORM framework within Haskell, so that if a user wants to make a database model, they would do something like this

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

Where the table would be "Car", and the columns would be the company,model,year

To do this within Haskell, you have to use a combination of classes and generics, and this is where I am getting stuck. Using this tutorial (http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/generic-programming.html), I came up with this (which was just basically copying and renaming so I can get the code working)

{-# 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)

The above code will produces the error

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

And I am kind of stuck at this point, I believe I have already instantiated all of the required Generic types to cover a record

解决方案

As kosmikus said in his comment, you cannot derive Model directly. First you need a 'front-end' class for Model providing a generic default, which could look like this:

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

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

Then you can just do:

Car = ... deriving Generic
instance FModel Car

And you have the desired instance.

这篇关于使用记录Haskell进行通用派生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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