哈斯克尔:反转地图'

时间:2016-04-06 01:46:10

标签: haskell

正如您在使用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

有谁知道解决这个问题的方法?如果你知道使用地图的更合适的功能,告诉我,我会调查它。

1 个答案:

答案 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