两个函数之间的 space 和使用组合运算符有什么区别?
What is the difference between a space between two functions and using the composition operator?
我试图定义一个函数来确定一个数字是否是 3 的倍数,我首先做了简单的案例
isMultipleOfThree num = (==0) (rem num 3)
但实际上,即使在那种简单的情况下,我的第一个猜测是像这样写我的解决方案
isMultipleOfThree num = (==0).(rem num 3)
哪个returns错误
Non type-variable argument in the constraint: Integral (a -> b) (Use
FlexibleContexts to permit this) When checking that
‘isMultipleOfThree’ has the inferred type isMultipleOfThree ::
forall b a.
(Eq b, Integral (a -> b), Num b) =>
(a -> b) -> a -> Bool
然后尝试让它更“多态”:
正确答案如下,但我认为我应该使用 space 而不是组合运算符......然后我只是“猜测”我会尝试使用组合运算符:
esMultiploDeTres = (==0).(flip (rem) 3)
所以我想我会添加到我原来的问题:“两个函数之间的 space 是什么?”
isMultipleOfThree num = (==0) (rem num 3)
(== 0)
称为运算符部分。它等同于 \x -> x == 0
,因此与
相同
isMultipleOfThree num = (\x -> x == 0) (rem num 3)
我们立即应用 lambda,所以我们得到
isMultipleOfThree num = rem num 3 == 0
现在,另一方面,你的第二个例子是
isMultipleOfThree num = (\x -> x == 0) . (rem num 3)
现在我们不是立即应用 lambda。我们正在应用 (.)
函数,其定义类似于
(.) :: (b -> c) -> (a -> b) -> (a -> c)
f . g = \y -> f (g y)
因此,我们有
isMultipleOfThree num = (\y -> (\x -> x == 0) ((rem num 3) y))
现在 x
上的 lambda 正被应用于一个参数,所以我们可以简化内部的
isMultipleOfThree num = (\y -> (rem num 3) y == 0)
并且 rem
周围的括号是无关紧要的,因此
isMultipleOfThree num = (\y -> rem num 3 y == 0)
因此,我们将 rem
一个具有两个参数的函数应用于三个参数。因此你的错误。
如果您想使用 (.)
来定义您的函数,我们可以。但是右边需要省略一个参数。
isMultipleOfThree = (== 0) . (\x -> rem x 3)
或
isMultipleOfThree = (== 0) . (`rem` 3)
请注意,我们不再提及您的函数参数 num
。右侧的构图正在等待争论。它将执行 (rem
3)on that argument and then compare the result against zero.
(.)works on functions, and both sides of the
(.)` operator should have an argument missing.
注意你可能想到的是($)
,大致定义为
($) :: (a -> b) -> (a -> b)
f $ x = f x
这真的只是功能应用。这不是作曲。我们可以轻松地将您的原始函数写成
isMultipleOfThree num = (== 0) $ (rem num 3)
($)
实际上确实表现得像并列。唯一的一点是改变运算符的优先级。在这种情况下我们可以省略括号
isMultipleOfThree num = (== 0) $ rem num 3
这仍然有效,而如果我们在您的原始函数中省略括号
isMultipleOfThree num = (==0) rem num 3 -- Wrong!
现在我们试图将 (==0)
函数应用于 三个 个参数,这绝对是不正确的。
(.)
简单定义为
# Apply g to x, then apply f to the result.
f . g = \x -> f (g x)
这意味着
(f . g) x == f (g x)
并列表示功能应用,而.
表示功能组合.
高阶函数,例如(.)
,可以将其他函数作为参数,这意味着您可以将这样的函数应用于另一个函数。 f . g
是一个中缀表达式,相当于前缀表达式 (.) f g
,其中 (.)
应用于 f
,结果应用于 g
。
我试图定义一个函数来确定一个数字是否是 3 的倍数,我首先做了简单的案例
isMultipleOfThree num = (==0) (rem num 3)
但实际上,即使在那种简单的情况下,我的第一个猜测是像这样写我的解决方案
isMultipleOfThree num = (==0).(rem num 3)
哪个returns错误
Non type-variable argument in the constraint: Integral (a -> b) (Use FlexibleContexts to permit this) When checking that ‘isMultipleOfThree’ has the inferred type isMultipleOfThree :: forall b a. (Eq b, Integral (a -> b), Num b) => (a -> b) -> a -> Bool
然后尝试让它更“多态”:
正确答案如下,但我认为我应该使用 space 而不是组合运算符......然后我只是“猜测”我会尝试使用组合运算符:
esMultiploDeTres = (==0).(flip (rem) 3)
所以我想我会添加到我原来的问题:“两个函数之间的 space 是什么?”
isMultipleOfThree num = (==0) (rem num 3)
(== 0)
称为运算符部分。它等同于 \x -> x == 0
,因此与
isMultipleOfThree num = (\x -> x == 0) (rem num 3)
我们立即应用 lambda,所以我们得到
isMultipleOfThree num = rem num 3 == 0
现在,另一方面,你的第二个例子是
isMultipleOfThree num = (\x -> x == 0) . (rem num 3)
现在我们不是立即应用 lambda。我们正在应用 (.)
函数,其定义类似于
(.) :: (b -> c) -> (a -> b) -> (a -> c)
f . g = \y -> f (g y)
因此,我们有
isMultipleOfThree num = (\y -> (\x -> x == 0) ((rem num 3) y))
现在 x
上的 lambda 正被应用于一个参数,所以我们可以简化内部的
isMultipleOfThree num = (\y -> (rem num 3) y == 0)
并且 rem
周围的括号是无关紧要的,因此
isMultipleOfThree num = (\y -> rem num 3 y == 0)
因此,我们将 rem
一个具有两个参数的函数应用于三个参数。因此你的错误。
如果您想使用 (.)
来定义您的函数,我们可以。但是右边需要省略一个参数。
isMultipleOfThree = (== 0) . (\x -> rem x 3)
或
isMultipleOfThree = (== 0) . (`rem` 3)
请注意,我们不再提及您的函数参数 num
。右侧的构图正在等待争论。它将执行 (rem
3)on that argument and then compare the result against zero.
(.)works on functions, and both sides of the
(.)` operator should have an argument missing.
注意你可能想到的是($)
,大致定义为
($) :: (a -> b) -> (a -> b)
f $ x = f x
这真的只是功能应用。这不是作曲。我们可以轻松地将您的原始函数写成
isMultipleOfThree num = (== 0) $ (rem num 3)
($)
实际上确实表现得像并列。唯一的一点是改变运算符的优先级。在这种情况下我们可以省略括号
isMultipleOfThree num = (== 0) $ rem num 3
这仍然有效,而如果我们在您的原始函数中省略括号
isMultipleOfThree num = (==0) rem num 3 -- Wrong!
现在我们试图将 (==0)
函数应用于 三个 个参数,这绝对是不正确的。
(.)
简单定义为
# Apply g to x, then apply f to the result.
f . g = \x -> f (g x)
这意味着
(f . g) x == f (g x)
并列表示功能应用,而.
表示功能组合.
高阶函数,例如(.)
,可以将其他函数作为参数,这意味着您可以将这样的函数应用于另一个函数。 f . g
是一个中缀表达式,相当于前缀表达式 (.) f g
,其中 (.)
应用于 f
,结果应用于 g
。