我试图手动评估fc [f1, f2] (\x -> 2) 3
但我没有意识到如何匹配三个参数:[f1,f2],(\ x - > 2)和3与函数定义,任何帮助?
功能定义:
fc xss = \f -> let ope x y = x . f . y in foldr1 ope xss
f1, f2 :: Int -> Bool
f1 x = (x `mod` 3) == 0
f2 x = (x `mod` 5) == 0
谢谢,
安。
答案 0 :(得分:4)
好吧,首先做一些η -expansion
fc :: [a->b] -> (b->a) -> a->b
fc xss f = let ope x y = x . f . y in \q -> foldr1 ope xss q
fc xss f q = let ope x y = x . f . y in foldr1 ope xss q
然后可能内联let
fc xss f q = foldr1 (\x y -> x . f . y) xss q
您可以将[f1, f2]
写为(==0).(`mod`3) : (==0).(`mod`5) : []
。
现在它应该很容易,记住右折叠只是用折叠函数替换所有:
。
答案 1 :(得分:1)
请记住,Haskell中的所有函数都是单个结果的单个参数的函数。
像func arg1 arg2 arg3
这样的表达式可能看起来就像应用于3个参数的函数一样,但它真的是((func arg1) arg2) arg3)
,其中func arg1
会产生新的函数,应用于arg2
以获取第3个函数,该函数最终应用于arg3
。
像func arg1 arg2 arg3 = ...
这样的定义是等同定义的语法糖,例如func arg1 = \arg2 -> (\arg3 -> ... )
,我们已经明确地写出了沿途产生的中间函数。
因此fc [f1, f2] (\x -> 2) 3
正在将fc
应用于[f1, f2]
,然后应用该结果。很清楚如何将fc
应用于一个参数(因为它的定义只有一个参数),所以我们只需要做第一步,看看我们得到了什么。
fc [f1, f2] = \f -> let ope x y = x . f . y in foldr1 ope [f1, f2]
这给了我们一个lambda函数,这是可以应用的东西。将其替换为原始表达式可以得到:
(\f -> let ope x y = x . f . y in foldr1 ope [f1, f2]) (\x -> 2) 3
现在我们再次将一个函数(\f -> ...
)应用于一个参数(\x -> 2
)。结果再次应用(3
),但我们稍后会担心。
(\f -> let ope x y = x . f . y in foldr1 ope [f1, f2]) (\x -> 2)
= let ope x y = x . (\x -> 2) . y in foldr1 ope [f1, f2]
这样就给了我们foldr1 ope [f1, f2]
的表达式,ope
的辅助定义let
;如果我们愿意,我们可以替换它,但我会让名字ope
保持原样。将其替换回来(记住我们已定义ope
):
(foldr1 ope [f1,f2])3
foldr
等同于以下内容:
foldr1 f [x] = x
foldr1 f (x:xs) = f x (foldr1 f xs)
因此,我们可以扩展foldr1
表达式,记住[f1, f2]
只是另一种写作方式f1:[f2]
:
foldr1 ope (f1:[f2]) = ope f1 (foldr1 ope [f2])
= ope f1 f2
替换回来给我们:
ope f1 f2 3
现在让我们使用我们预留的ope的定义:ope x y = x . (\x -> 2) . y
(同样,我们可以在之前替换它,但它只是意味着在我们编写的所有地方复制出定义{{1 }} 以上)。记住ope
实际上是单个参数的函数,即使我们被允许定义它看起来像是为了方便它有两个参数,让我们一次应用一个参数: / p>
ope
所以我们现在有:
ope f1 = \y -> f1 . (\x -> 2) . y
应用lambda给我们:
(\y -> f1 . (\x -> 2) . y) f2 3
终于我们发现(f1 . (\x -> 2) . f2) 3
是作文的一个参数"管道" 3
。我将在此停止,但您可以使用f1 . (\x -> 2) . f2
的定义进一步扩展,并找出传递给最终函数.
的内容。
因此,原始表达式中的3个值3
,[f1, f2]
和(\x -> 2)
不需要直接匹配为3
定义的参数,因为他们根本不是所有的论据。 fc
是[f1, f2]
的参数,fc
是一个由(\x -> 2)
简单计算的参数(因此您可以将其视为"第二个参数&#34 ;如果你愿意,可以fc [f1, f2]
;重写fc
的等式非常容易,因此它可以直接作为参数出现。另一方面,fc
不是一个函数的参数,它与源代码中直接写入的函数有关,它最终被传递给计算的函数表达式3
。