Haskell:创建一个只包含某些“信息”的列表;“种类”;类型?
我一直在努力学习Haskell和开始Haskell,发现了一个有趣的问题。在前言中,我通常是C++程序员,所以如果我不知道我在说什么,请原谅我。 Haskell开头的一个练习让我创建一个类型客户机,它可以是政府组织、公司或个人。我决定为此尝试记录语法Haskell:创建一个只包含某些“信息”的列表;“种类”;类型?,haskell,types,coding-style,Haskell,Types,Coding Style,我一直在努力学习Haskell和开始Haskell,发现了一个有趣的问题。在前言中,我通常是C++程序员,所以如果我不知道我在说什么,请原谅我。 Haskell开头的一个练习让我创建一个类型客户机,它可以是政府组织、公司或个人。我决定为此尝试记录语法 data Client = GovOrg { name :: String } | Company { name :: String, id :: Integer,
data Client = GovOrg { name :: String }
| Company { name :: String,
id :: Integer,
contact :: String,
position :: String
}
| Individual { fullName :: Person,
offers :: Bool
}
deriving Show
data Person = Person { firstName :: String,
lastName :: String,
gender :: Gender
}
deriving Show
data Gender = Male | Female | Unknown
deriving Show
这是用于一个练习,在这个练习中,给定一个客户列表,我必须找出每个性别中有多少人在列表中。我开始筛选,以获得一个只有个人的列表,因为只有他们有性别类型,但我的方法似乎完全错误:
listIndividuals :: [Client] -> [Client]
listIndividuals xs = filter (\x -> x == Individual) xs
我如何获得这个功能,在这里我可以检查什么是“类型”的客户端。同样对于记录语法,我的编码风格如何?太不一致了?首先,我建议不要将记录类型与代数类型一起使用,因为最终会使用部分访问器函数。例如,让code
位置(个人(personal,“John”“Doe”Person)为True)是完全合法的
,但它会引发运行时错误。相反,考虑一些更像
data GovClient = GovClient {
govName :: String
} deriving Show
data CompanyClient = CompanyClient {
companyName :: String,
companyID :: Integer, -- Also, don't overwrite existing names, `id` is built-in function
companyContact :: String,
companyPosition :: String
} deriving Show
data IndividualClient = IndividualClient {
indvFullName :: Person,
indvOffers :: Bool
} deriving Show
那你就可以
data Client
= GovOrg GovClient
| Company CompanyClient
| Individual IndividualClient
deriving (Show)
现在您还可以将函数定义为
isIndividualClient :: Client -> Bool
isIndividualClient (Individual _) = True
isIndividualClient _ = False
listIndividuals :: [Client] -> [IndividualClient]
listIndividuals clients = filter isIndividualClient clients
或者更无点形式的
listIndividuals = filter isIndividualClient
在这里,为了做出决定,我只是在一个单独的函数中使用模式匹配来确定使用了客户机的构造函数中的哪一个。现在,您可以使用记录和代数类型的全部功能,只需再担心一点点代码,但安全性要高得多。例如,您永远不会意外地在单个客户机上调用一个需要政府客户机的函数,因为它不会进行类型检查,而在当前的实现中,这是完全可能的
如果您关心较长的名称,我建议您最终查看lens
库,该库旨在帮助您相对轻松地操作复杂的记录类型树
使用当前的实现,您还可以做一些与最终解决方案非常类似的事情:
isIndividualClient :: Client -> Bool
isIndividualClient (Individual _ _) = True
isIndividualClient _ = False
listIndividuals :: [Client] -> [Client]
listIndividuals clients = filter isIndividualClient clients
这里的主要区别是,Individual
接受两个字段,因此我在模式中有两个
通配符匹配,listIndividuals
的类型现在是[Client]->[Client]
首先,我建议不要使用代数类型的记录类型,因为您最终使用了部分访问器函数。例如,让code位置(个人(personal,“John”“Doe”Person)为True)是完全合法的
,但它会引发运行时错误。相反,考虑一些更像
data GovClient = GovClient {
govName :: String
} deriving Show
data CompanyClient = CompanyClient {
companyName :: String,
companyID :: Integer, -- Also, don't overwrite existing names, `id` is built-in function
companyContact :: String,
companyPosition :: String
} deriving Show
data IndividualClient = IndividualClient {
indvFullName :: Person,
indvOffers :: Bool
} deriving Show
那你就可以
data Client
= GovOrg GovClient
| Company CompanyClient
| Individual IndividualClient
deriving (Show)
现在您还可以将函数定义为
isIndividualClient :: Client -> Bool
isIndividualClient (Individual _) = True
isIndividualClient _ = False
listIndividuals :: [Client] -> [IndividualClient]
listIndividuals clients = filter isIndividualClient clients
或者更无点形式的
listIndividuals = filter isIndividualClient
在这里,为了做出决定,我只是在一个单独的函数中使用模式匹配来确定使用了客户机的构造函数中的哪一个。现在,您可以使用记录和代数类型的全部功能,只需再担心一点点代码,但安全性要高得多。例如,您永远不会意外地在单个客户机上调用一个需要政府客户机的函数,因为它不会进行类型检查,而在当前的实现中,这是完全可能的
如果您关心较长的名称,我建议您最终查看lens
库,该库旨在帮助您相对轻松地操作复杂的记录类型树
使用当前的实现,您还可以做一些与最终解决方案非常类似的事情:
isIndividualClient :: Client -> Bool
isIndividualClient (Individual _ _) = True
isIndividualClient _ = False
listIndividuals :: [Client] -> [Client]
listIndividuals clients = filter isIndividualClient clients
<> P>主要区别在于,代码>个人<代码>两个字段,因此在模式中有两个<代码> > <代码>通配符匹配,并且 >类型的个人> <代码>现在是代码> [客户端] > [客户端] < /> > <代码> x==个人< /代码> -如果你来自C++,你应该知道这没有意义。Yea,我的想法很糟糕。这就像说5==int
。但这似乎并不是因为,据我的理解,个体是一个值构造函数,而不是一个类型。所以我想我的问题更多的是如何检查客户的价值,“如何检查客户的价值”。模式匹配<代码> x==个人< /代码>——如果你来自C++,你应该知道这没有意义。Yea,我的想法不好。这就像说5==int
。但这似乎并不是因为,据我的理解,个体是一个值构造函数,而不是一个类型。所以我想我的问题更多的是如何检查客户的价值,“如何检查客户的价值”。图案匹配灯,谢谢!我想我在以这种方式使用记录类型方面有点超前了。@mal20k如果您真的在API中确信永远不会执行非法操作,那么这样做很好,但通常我建议将其拆分为由单个ADT统一的单独类型。当然,它在您的记录上添加了一层额外的类型,但是您获得了很多安全性,并且在许多情况下,您的类型将更有意义。即使在这个小示例中,listIndividuals
的类型也变得更能表达它实际在做什么。正是这些微小的差异需要经验来发现,所以不要对自己太苛刻!好的,谢谢!我想我在以这种方式使用记录类型方面有点超前了。@mal20k如果您真的在API中确信永远不会执行非法操作,那么这样做很好,但通常我建议将其拆分为由单个ADT统一的单独类型。当然,它在您的记录上添加了一层额外的类型,但是您获得了很多安全性,并且在许多情况下,您的类型将更有意义。即使在这个小示例中,listIndividuals
的类型也变得更能表达它实际在做什么。就是这些小东西