外部产品 - >部分应用的功能 - >组成

时间:2016-05-11 14:20:00

标签: haskell

我有一个二进制函数列表,例如(a -> b -> a)和项目列表[b]。我需要按如下方式生成转换(a -> a)。对于每个b,我需要部分应用函数并生成它们的组合,这给了我一个与bs长度相同的一元函数列表。将这些作品中的每一个称为处理器;我接下来需要编写处理器。例如,如果我有函数[f0,f1]和项[b0,b1],我需要函数(f1 b1) . (f0 b1) . (f1 b0) . (f0 b0)。我可以看到我在bs上折叠,但这也看起来像是外部产品的组合。那么,Haskell是否提供了一种巧妙的方法来生产某种外部产品? (当然,订单很重要。)如果是这样,请用一个完整新手可以理解的术语解释。

2 个答案:

答案 0 :(得分:3)

有关仅使用标准功能的解决方案,请参阅ThreeFx's answer

您还需要使用(.)折叠部分应用的函数列表。

首先,获取部分应用函数的列表:

-- If f :: a -> b -> a, then (`f` b) :: a -> a
[ (`f` b) | b <- [b0, b1], f <- [f0, f1] ]
-- Result: [(`f0` b0), (`f1` b0), (`f0` b1), (`f1` b1)]

(使用fs <*> bs会很好,但您需要将f部分应用于其第二个参数,而不是第一个,并且结果列表的顺序错误对于组成步骤。)

接下来,使用(.)折叠该列表。我永远不会完全记住使用哪个折叠(或如何使用它来确保您需要的正确顺序),所以这是一个自定义递归函数,我知道这是正确的:

composeAll :: [(a -> a)]
composeAll [] = id
composeAll (f:fs) = composeAll fs . f

全部放在一起:

fs = [f0, f1, f2]
bs = [b0, b1, b2]
f = composeAll [(`f` b) | b <- bs, f <- fs]

答案 1 :(得分:3)

您可以使用<**>(位于Control.Applicative)和fold结果:

combine :: [(a -> b -> a)] -> [b] -> (a -> a)
combine fs bs = foldr (flip (.)) id $ bs <**> (map flip fs)

让我们来看看组件:

map flip fs

这只是将函数从a -> b -> a翻转到b -> a -> a,以便我们稍后可以ap

bs <**> (map flip fs)
-- ex: [b0, b1] <**> [f0, f1] == [f0 b0, f1 b0, f0 b1, f1 b1]

此功能部分将所有bs应用于fs并将其放入列表中。我们现在要做的就是使用合成运算符fold(.)结果。请注意,使用flip (.)我们会反转合成顺序,因为<**>生成的列表与我们想要的相反:

foldr (flip (.)) id $ it -- alternatively foldr1
-- ex: foldr (flip (.)) id [f0 b0, f1 b0, f0 b1, f1 b1] ==
--     (f1 b1) . (f0 b1) . (f1 b0) . (f0 b0)