在Haskell中建模域数据 [英] Modeling domain data in Haskell
问题描述
我首先写出我的域/值对象。一个例子是用户。这是我到目前为止
模块模型(用户)其中
类审计a where
creationDate :: a - >整数
lastUpdatedDate :: a - >整数
creationUser :: a - > User
lastUpdatedUser :: a - >用户
类标识了哪里
id :: a - >整数
数据User = User {userId :: Integer
,userEmail :: String
,userCreationDate :: Integer $ b $,userLastUpdatedDate :: Integer
, userCreationUser :: User
,userLastUpdatedUser :: User
}
实例已识别用户其中
id u = userId u
实例审计用户其中
creationDate u = userCreationDate
lastUpdatedDate u = userLastUpdatedDate
creationUser u = userCreationUser
lastUpdatedUser u = userLastUpdatedUser
我的应用程序大概有20种类型,就像上面的类型一样。当我说像上面的类型,我的意思是他们将有一个ID,审计信息和一些类型特定的信息(例如用户的电子邮件)。
我无法打包的事情是,我的每个字段(例如User.userEmail)都会创建一个新函数 fieldName :: Type - >的FieldType
。有20种不同的类型,名称空间看起来好像会变得相当快。另外,我不喜欢必须命名我的用户ID字段 userId
。我宁愿将它命名为 id
。有没有办法解决这个问题?
也许我应该提一提,我是来自势在必行的世界,所以这个FP的东西对我来说是非常新的(但非常令人兴奋) 。
是的,在Haskell中,命名空间可能是一种痛苦。我通常最终会收紧我的抽象,直到没有那么多的名字。它也允许更多的重用。对于你的,我会为数据类型而不是审计信息的类:
data审计=审计{
creationDate :: Integer,
lastUpdatedDate :: Integer,
creationUser :: User,
lastUpdatedUser :: User
}
然后将其与特定于类型的数据配对:
data User = User {
userAudit :: Audit,
userId :: Integer,
userEmail :: String
}
如果您想要的话,您仍然可以使用这些类型类:
class Audited a where
audit :: a - >审计
类识别出哪里
ident :: a - >整数
然而,随着你的设计的发展,对于那些特种类溶解在稀薄空气中的可能性开放。 类对象类型类 - 其中每个方法接受类型为 a
的单个参数的类型类 - 可以简化它们。
解决这个问题的另一种方法是使用参数类型对对象进行分类:
data Object a = Object {
objId :: Integer,
objAudit :: Audit,
objData :: a
}
检查出来, 根据我的设计预感,我会更倾向于这样做。如果不知道更多关于计划的信息,很难说哪种方式更好。并且看,这些类型特定物质需要溶解掉。 : - ) I'm working on designing a larger-ish web application using Haskell. This is purely for my education and interest. I'm starting by writing out my domain/value objects. One example is a User. Here's what I've come up with so far My application will have roughly 20 types like the above type. When I say "like the above type", I mean they will have an id, audit information, and some type-specific information (like email in the case of User). The thing I can't wrap my mind around is the fact that each of my fields (e.g. User.userEmail) creates a new function Maybe I should mention that I'm coming from the imperative world, so this FP stuff is pretty new (yet pretty exciting) for me. Yeah, namespacing can be kind of a pain in Haskell. I usually end up tightening up my abstractions until there are not so many names. It also allows for more reuse. For yours, I would make a data type rather than a class for the audit information: And then pair that up with the type-specific data: You can still use those typeclasses if you want: However as your design develops, be open to the possibility of those typeclasses dissolving into thin air. Object-like typeclasses -- ones where every method takes a single parameter of type Another way to approach this might be to classify your objects with a parametric type: Check it out, I would be more inclined to do it this way, based on my design hunch. It is hard to say which way is better without knowing more about your plans. And look, the need for those typeclasses dissolved away. :-) 这篇关于在Haskell中建模域数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! Object 是
Functor $ c $
$ $ p $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ )
module Model (User) where
class Audited a where
creationDate :: a -> Integer
lastUpdatedDate :: a -> Integer
creationUser :: a -> User
lastUpdatedUser :: a -> User
class Identified a where
id :: a -> Integer
data User = User { userId :: Integer
, userEmail :: String
, userCreationDate :: Integer
, userLastUpdatedDate :: Integer
, userCreationUser :: User
, userLastUpdatedUser :: User
}
instance Identified User where
id u = userId u
instance Audited User where
creationDate u = userCreationDate
lastUpdatedDate u = userLastUpdatedDate
creationUser u = userCreationUser
lastUpdatedUser u = userLastUpdatedUser
fieldName :: Type -> FieldType
. With 20 different types, the namespace seems like it'll get pretty full pretty fast. Also, I don't like having to name my User ID field userId
. I'd rather name it id
. Is there any way around this?data Audit = Audit {
creationDate :: Integer,
lastUpdatedDate :: Integer,
creationUser :: User,
lastUpdatedUser :: User
}
data User = User {
userAudit :: Audit,
userId :: Integer,
userEmail :: String
}
class Audited a where
audit :: a -> Audit
class Identified a where
ident :: a -> Integer
a
-- have a way of simplifying themselves away.data Object a = Object {
objId :: Integer,
objAudit :: Audit,
objData :: a
}
Object
is a Functor
!instance Functor Object where
fmap f (Object id audit dta) = Object id audit (f dta)