3 回答
TA贡献1811条经验 获得超4个赞
正如Lambdageek所建议的,这就是使用语义编辑器组合器(SEC)的方式。
首先是几个有用的缩写:
type Unop a = a -> a
type Lifter p q = Unop p -> Unop q
这Unop是一个“语义编辑器”,并且Lifter是语义编辑器的组合器。一些起重器:
onManager :: Lifter Coach BBTeam
onManager f (BBTeam n m p) = BBTeam n (f m) p
onDiet :: Lifter Diet Coach
onDiet f (Coach n c d) = Coach n c (f d)
onStakes :: Lifter Integer Diet
onStakes f (Diet n s e) = Diet n (f s) e
现在,只需简单地使SEC组成即可说出您想要的内容,即在(经理)经理的饮食中加1:
addManagerSteak :: Unop BBTeam
addManagerSteak = (onManager . onDiet . onStakes) (+1)
与SYB方法相比,SEC版本需要额外的工作来定义SEC,而我仅在此示例中提供了所需的内容。SEC允许有针对性的应用程序,如果玩家节食但我们不想对其进行调整,这将很有帮助。也许还有一种很漂亮的SYB方法来处理这种区别。
编辑:这是基本SEC的替代样式:
onManager :: Lifter Coach BBTeam
onManager f t = t { manager = f (manager t) }
TA贡献1827条经验 获得超9个赞
稍后,您可能还需要看一下一些通用的编程库:当数据的复杂性增加并且发现自己编写了更多的样板代码(例如,增加了球员,教练的饮食和看守者的啤酒含量)时,即使是不太冗长的形式,也仍然是样板。 SYB可能是最著名的库(Haskell Platform附带)。实际上,有关SYB的原始论文使用了非常相似的问题来演示该方法:
考虑以下描述公司组织结构的数据类型。公司分为部门。每个部门都有一个经理,并且由一组子部门组成,其中一个部门可以是一个雇员或一个部门。经理和普通雇员都是领薪的人。
[跳过]
现在假设我们想将公司中每个人的薪水提高指定的百分比。也就是说,我们必须编写函数:
增加::浮动->公司->公司
(其余内容在论文中-建议阅读)
当然,在您的示例中,您只需要访问/修改一个微小数据结构的一部分,因此它不需要通用方法(仍然在下面为您的任务提供基于SYB的解决方案),但是一旦您看到重复的代码/访问/模式您想检查此修改或其他通用编程库。
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Generics
data BBTeam = BBTeam { teamname :: String,
manager :: Coach,
players :: [BBPlayer]} deriving (Show, Data, Typeable)
data Coach = Coach { coachname :: String,
favcussword :: String,
diet :: Diet } deriving (Show, Data, Typeable)
data Diet = Diet { dietname :: String,
steaks :: Integer,
eggs :: Integer} deriving (Show, Data, Typeable)
data BBPlayer = BBPlayer { playername :: String,
hits :: Integer,
era :: Double } deriving (Show, Data, Typeable)
incS d@(Diet _ s _) = d { steaks = s+1 }
addManagerSteak :: BBTeam -> BBTeam
addManagerSteak = everywhere (mkT incS)
- 3 回答
- 0 关注
- 379 浏览
添加回答
举报