我正在使用Haskell设计更大的Web应用程序.这纯粹是为了我的教育和兴趣.
我首先写出我的域/值对象.一个例子是用户.这是我到目前为止所提出的
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
Run Code Online (Sandbox Code Playgroud)
我的应用程序将有大约20种类型,如上述类型.当我说"像上面的类型"时,我的意思是他们会有一个id,审核信息和一些特定类型的信息(比如用户的电子邮件).
我无法理解的事实是我的每个字段(例如User.userEmail)都创建了一个新函数fieldName :: Type -> FieldType.有20种不同的类型,命名空间似乎很快就会变得非常完整.此外,我不喜欢必须命名我的用户ID字段userId.我宁愿给它起个名字id.有没有办法解决?
也许我应该提一下,我是来自势在必行的世界,所以这个FP的东西对我来说是相当新的(但非常令人兴奋).
luq*_*qui 14
是的,命名空间可能是Haskell的一种痛苦.我通常最终收紧我的抽象,直到没有那么多名字.它还允许更多的重用.对于你的,我会为审计信息创建数据类型而不是类:
data Audit = Audit {
creationDate :: Integer,
lastUpdatedDate :: Integer,
creationUser :: User,
lastUpdatedUser :: User
}
Run Code Online (Sandbox Code Playgroud)
然后将其与特定类型的数据配对:
data User = User {
userAudit :: Audit,
userId :: Integer,
userEmail :: String
}
Run Code Online (Sandbox Code Playgroud)
如果需要,您仍然可以使用这些类型类:
class Audited a where
audit :: a -> Audit
class Identified a where
ident :: a -> Integer
Run Code Online (Sandbox Code Playgroud)
然而,随着您的设计的发展,对这些类型化合物溶解在稀薄空气中的可能性持开放态度. 类似对象的类型类 - 每个方法都采用单个类型参数的类型a- 有一种简化自己的方法.
另一种解决方法可能是使用参数类型对对象进行分类:
data Object a = Object {
objId :: Integer,
objAudit :: Audit,
objData :: a
}
Run Code Online (Sandbox Code Playgroud)
看看,Object是一个Functor!
instance Functor Object where
fmap f (Object id audit dta) = Object id audit (f dta)
Run Code Online (Sandbox Code Playgroud)
基于我的设计预感,我更倾向于这样做.如果不了解更多有关您的计划,很难说哪种方式更好.看,这些类型的需求消失了.:-)
这是Haskell记录的一个已知问题.已经有一些建议(特别是TDNR)来减轻影响,但尚未出现任何解决方案.
如果您不介意将每个数据对象放在一个单独的模块中,那么您可以使用命名空间来区分这些函数:
import qualified Model.User as U
import qualified Model.Privileges as P
someUserId user = U.id user
somePrivId priv = P.id priv
Run Code Online (Sandbox Code Playgroud)
至于用来id代替userId; id默认情况下,隐藏从Prelude导入的内容是可能的.使用以下作为第一个import语句:
import Prelude hiding (id)
Run Code Online (Sandbox Code Playgroud)
现在通常的id功能不在范围内.如果由于某种原因需要它,您可以使用完全限定的名称访问它,即Prelude.id.
在创建与Prelude冲突的名称之前,请仔细考虑.程序员经常会感到困惑,而且工作起来有点尴尬.你可能最好使用简短的通用名称,例如oId.