正如您在使用map时可能已经知道的那样,它会重新生成一个函数并将该函数应用于列表的每个元素
map f xs is the list obtained by applying f to each element of xs, i.e.,
但在我的情况下,我有一个需要应用的功能列表,以便达到特定的值。这是类型,以提供更好的想法:
data Auto = Auto {plate :: String, currentTank :: Int, tanqSize :: Int} deriving (Show, Eq)
type Services = Car -> Car
service :: Car -> [Services] -> Car
正如我之前解释的那样,[服务]将是一个功能列表,其中包括“汽车”和“汽车”。并返回' Car'。我需要将这些功能应用到“汽车”中。重新提供服务'并在完成所有修改后返回。
以下是列表中可能出现的一些功能示例:
emptyTank :: Services
reFuel :: Int -> Services
changePlate :: String -> Services
upgradeTank :: Int -> Services
有谁知道解决这个问题的方法?如果你知道使用地图的更合适的功能,告诉我,我会调查它。
答案 0 :(得分:2)
您可以使用foldl
:
service :: Car -> [Services] -> Car
service car functions = foldl (flip ($)) car functions
service someCar [emptyTank, (refuel 10), (changePlate "abc 123"), (upgradeTank 15)]
($)
是函数应用程序,但要与foldl
一起使用(为了以正确的顺序应用函数,我们需要翻转它的参数,以便arg $ f
求值为{{1将f arg
与(flip ($))
一起使用会导致foldl
中的第一个函数应用于functions
,然后第二个函数将应用于第一个函数的结果,然后第三个到第二个结果,等等。
(car
可以与foldr
代替($)
一起使用,但它会从右到左应用函数,而不是从左到右。比较
flip ($)
与
foldl (flip ($)) 3 [(+4), (*5)] -- Returns (3+4)*5 = 35
)
另一种看待这种情况的方法是,您希望将函数列表组合成一个函数:
foldr ($) 3 [(+4), (*5)] -- Returns (3*5) + 4 = 19
你也可以使用(upgradeTank 15) . (changePlate "abc 123") . (refuel 10) . emptyTank $ someCar
(或foldl
?这似乎没有区别你在这里使用),使用foldr
将列表缩减为单个函数,然后将该函数应用于(.)
。 car
函数用作id
对(.)
的第一次调用的另一个参数。但是,您确实需要首先反转函数列表,因为组合是右关联的。
foldl