Haskell 中的点运算符:需要更多解释
我试图理解点运算符在这个 Haskell 代码中做了什么:
sumEuler = sum . (map euler) . mkList
整个源代码如下。
我的理解
点运算符是将两个函数sum和map euler的结果以及mkList的结果作为输入。
但是,sum 不是一个函数,它是函数的参数,对吧? 那么这是怎么回事呢?
另外,(map euler)
在做什么?
代码
mkList :: Int -> [Int]
mkList n = [1..n-1]
euler :: Int -> Int
euler n = length (filter (relprime n) (mkList n))
sumEuler :: Int -> Int
sumEuler = sum . (map euler) . mkList
I'm trying to understand what the dot operator is doing in this Haskell code:
sumEuler = sum . (map euler) . mkList
The entire source code is below.
My understanding
The dot operator is taking the two functions sum
and the result of map euler
and the result of mkList
as the input.
But, sum
isn't a function it is the argument of the function, right? So what is going on here?
Also, what is (map euler)
doing?
Code
mkList :: Int -> [Int]
mkList n = [1..n-1]
euler :: Int -> Int
euler n = length (filter (relprime n) (mkList n))
sumEuler :: Int -> Int
sumEuler = sum . (map euler) . mkList
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
简而言之,
.
是函数组合,就像数学中一样:它也可以这样定义:
在您的例子中,您正在创建一个新函数
sumEuler
, 你的例子被称为“无点”风格——函数的参数被省略。 在许多情况下,这使得代码更加清晰。 (第一次看到它可能很难理解,但一段时间后你就会习惯它。这是一个常见的 Haskell 习惯用法。)如果你仍然感到困惑,关联
可能会有所帮助。 到类似于 UNIX 管道的东西。 如果
f
的输出成为g
的输入,其输出又成为h
的输入,您可以将其写在命令行上就像f < x| 克| h
. 在 Haskell 中,.
的工作方式类似于 UNIX|
,但“向后”——h 。 G 。 f$x
。 我发现这个符号在处理列表时非常有用。 您可以只编写(+10) ,而不是像
。 (并且,如果您只想将该函数应用于单个值;它是map (\x -> x * 2 + 10) [1..10]
这样的笨重结构。 (*2) <$>; [1..10](+10) . (*2) $ 10
。一致!)Haskell wiki 有一篇很好的文章,其中包含更多详细信息:http://www.haskell.org/haskellwiki/Pointfree
Put simply,
.
is function composition, just like in math:In your case, you are creating a new function,
sumEuler
that could also be defined like this:The style in your example is called "point-free" style -- the arguments to the function are omitted. This makes for clearer code in many cases. (It can be hard to grok the first time you see it, but you will get used to it after a while. It is a common Haskell idiom.)
If you are still confused, it may help to relate
.
to something like a UNIX pipe. Iff
's output becomesg
's input, whose output becomesh
's input, you'd write that on the command-line likef < x | g | h
. In Haskell,.
works like the UNIX|
, but "backwards" --h . g . f $ x
. I find this notation to be quite helpful when, say, processing a list. Instead of some unwieldy construction likemap (\x -> x * 2 + 10) [1..10]
, you could just write(+10) . (*2) <$> [1..10]
. (And, if you want to only apply that function to a single value; it's(+10) . (*2) $ 10
. Consistent!)The Haskell wiki has a good article with some more detail: http://www.haskell.org/haskellwiki/Pointfree
这 。 运算符组成函数。 例如,
其中 a 和 b 是函数,这是一个新的函数,它在其参数上运行 b,然后在这些结果上运行 a。 您的代码
与:
但希望更容易阅读。 map euler 周围有括号的原因是它更清楚地表明有 3 个函数组成:sum、map euler 和 >mkList - map euler 是一个函数。
The . operator composes functions. For example,
Where a and b are functions is a new function that runs b on its arguments, then a on those results. Your code
is exactly the same as:
but hopefully easier to read. The reason there are parens around map euler is because it makes it clearer that there are 3 functions being composed: sum, map euler and mkList - map euler is a single function.
sum
是 Haskell Prelude 中的函数,而不是sumEuler
的参数。 它具有类型函数组合运算符
.
具有类型所以我们有
注意,
Int
确实是Num
类型类的实例。sum
is a function in the Haskell Prelude, not an argument tosumEuler
. It has the typeThe function composition operator
.
has typeSo we have
Note that
Int
is indeed an instance of theNum
typeclass.这 。 运算符用于函数组合。 就像数学一样,如果您必须使用 f(x) 和 g(x) f 函数。 g 变为 f(g(x))。
map 是一个内置函数,它将函数应用于列表。 通过将函数放在括号中,该函数将被视为参数。 对此的术语是柯里化。 你应该查一下。
它的作用是,它接受一个带有两个参数的函数,它应用参数 euler。 (地图欧拉)对吧? 结果是一个新函数,它只接受一个参数。
总和。 (地图欧拉)。 mkList 基本上是一种将所有这些组合在一起的奇特方式。 我必须说,我的 Haskell 有点生疏,但也许你可以自己把最后一个函数组合起来?
The . operator is used for function composition. Just like math, if you have to functions f(x) and g(x) f . g becomes f(g(x)).
map is a built-in function which applies a function to a list. By putting the function in parentheses the function is treated as an argument. A term for this is currying. You should look that up.
What is does is that it takes a function with say two arguments, it applies the argument euler. (map euler) right? and the result is a new function, which takes only one argument.
sum . (map euler) . mkList is basically a fancy way of putting all that together. I must say, my Haskell is a bit rusty but maybe you can put that last function together yourself?
简答
不带点的等效代码,即只有
或没有 lambda,
因为点 (.) 表示函数组合。
更长的答案
首先,让我们简化
euler
到map
的部分应用:现在我们只有点。 这些点表示什么?
来自来源:
因此
(.)
是组合运算符。组合
在数学中,我们可以将函数 f(x) 和 g(x) 的组合写成,即 f(g(x)),如下
可以读作“f 由 g 组成”。
因此,在 Haskell 中,f ∘ g 或由 g 组成的 f 可以写成:
组合是结合律的,这意味着用组合运算符编写的 f(g(h(x))) 可以省略括号而不会产生任何歧义。
也就是说,由于 (f ∘ g) ∘ h 等价于 f ∘ (g ∘ h),所以我们可以简单地写成 f ∘ g ∘ h。
回到
我们之前的简化,这:
仅仅意味着
sumEuler
是这些函数的未应用的组合:Short answer
Equivalent code without dots, that is just
or without the lambda
because the dot (.) indicates function composition.
Longer answer
First, let's simplify the partial application of
euler
tomap
:Now we just have the dots. What is indicated by these dots?
From the source:
Thus
(.)
is the compose operator.Compose
In math, we might write the composition of functions, f(x) and g(x), that is, f(g(x)), as
which can be read "f composed with g".
So in Haskell, f ∘ g, or f composed with g, can be written:
Composition is associative, which means that f(g(h(x))), written with the composition operator, can leave out the parentheses without any ambiguity.
That is, since (f ∘ g) ∘ h is equivalent to f ∘ (g ∘ h), we can simply write f ∘ g ∘ h.
Circling back
Circling back to our earlier simplification, this:
just means that
sumEuler
is an unapplied composition of those functions:点运算符将左侧函数 (
sum
) 应用到右侧函数的输出。 在您的例子中,您将多个函数链接在一起 - 将mkList
的结果传递给(map euler)
,然后将其结果传递给总和。
此网站< /a> 对几个概念有很好的介绍。
The dot operator applies the function on the left (
sum
) to the output of the function on the right. In your case, you're chaining several functions together - you're passing the result ofmkList
to(map euler)
, and then passing the result of that tosum
.This site has a good introduction to several of the concepts.