Haskell 中的点运算符:需要更多解释

发布于 2024-07-14 18:23:11 字数 541 浏览 17 评论 0原文

我试图理解点运算符在这个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

何时共饮酒 2024-07-21 18:23:11

简而言之, . 是函数组合,就像数学中一样:

f (g x) = (f . g) x

它也可以这样定义:

sumEuler x = sum (map euler (mkList x))

在您的例子中,您正在创建一个新函数 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:

f (g x) = (f . g) x

In your case, you are creating a new function, sumEuler that could also be defined like this:

sumEuler x = sum (map euler (mkList x))

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. If f's output becomes g's input, whose output becomes h's input, you'd write that on the command-line like f < 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 like map (\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

拍不死你 2024-07-21 18:23:11

这 。 运算符组成函数。 例如,

a . b

其中 ab 是函数,这是一个新的函数,它在其参数上运行 b,然后在这些结果上运行 a。 您的代码

sumEuler = sum . (map euler) . mkList

与:

sumEuler myArgument = sum (map euler (mkList myArgument))

但希望更容易阅读。 map euler 周围有括号的原因是它更清楚地表明有 3 个函数组成:summap euler>mkList - map euler 是一个函数。

The . operator composes functions. For example,

a . b

Where a and b are functions is a new function that runs b on its arguments, then a on those results. Your code

sumEuler = sum . (map euler) . mkList

is exactly the same as:

sumEuler myArgument = sum (map euler (mkList myArgument))

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.

拥有 2024-07-21 18:23:11

sum 是 Haskell Prelude 中的函数,而不是 sumEuler 的参数。 它具有类型

Num a => [a] -> a

函数组合运算符 . 具有类型

(b -> c) -> (a -> b) -> a -> c

所以我们有

           euler           ::  Int -> Int
       map                 :: (a   -> b  ) -> [a  ] -> [b  ]
      (map euler)          ::                 [Int] -> [Int]
                    mkList ::          Int -> [Int]
      (map euler) . mkList ::          Int ->          [Int]
sum                        :: Num a =>                 [a  ] -> a
sum . (map euler) . mkList ::          Int ->                   Int

注意,Int 确实是 Num 类型类的实例。

sum is a function in the Haskell Prelude, not an argument to sumEuler. It has the type

Num a => [a] -> a

The function composition operator . has type

(b -> c) -> (a -> b) -> a -> c

So we have

           euler           ::  Int -> Int
       map                 :: (a   -> b  ) -> [a  ] -> [b  ]
      (map euler)          ::                 [Int] -> [Int]
                    mkList ::          Int -> [Int]
      (map euler) . mkList ::          Int ->          [Int]
sum                        :: Num a =>                 [a  ] -> a
sum . (map euler) . mkList ::          Int ->                   Int

Note that Int is indeed an instance of the Num typeclass.

枯寂 2024-07-21 18:23:11

这 。 运算符用于函数组合。 就像数学一样,如果您必须使用 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?

许久 2024-07-21 18:23:11

Haskell 中的点运算符

我试图理解点运算符在此 Haskell 代码中的作用:

sumEuler = sum 。   (地图欧拉)。   MK列表 
  

简答

不带点的等效代码,即只有

sumEuler = \x -> sum ((map euler) (mkList x))

或没有 lambda,

sumEuler x = sum ((map euler) (mkList x))

因为点 (.) 表示函数组合。

更长的答案

首先,让我们简化 eulermap 的部分应用:

map_euler = map euler
sumEuler = sum . map_euler . mkList

现在我们只有点。 这些点表示什么?

来自来源

(.) :: (b -> c) ->   (a→b)→   一个->   C 
  (.) fg = \x ->   f(gx) 
  

因此 (.)组合运算符

组合

在数学中,我们可以将函数 f(x) 和 g(x) 的组合写成,即 f(g(x)),如下

(f ∘ g)(x)

可以读作“f 由 g 组成”。

因此,在 Haskell 中,f ∘ g 或由 g 组成的 f 可以写成:

f . g

组合是结合律的,这意味着用组合运算符编写的 f(g(h(x))) 可以省略括号而不会产生任何歧义。

也就是说,由于 (f ∘ g) ∘ h 等价于 f ∘ (g ∘ h),所以我们可以简单地写成 f ∘ g ∘ h。

回到

我们之前的简化,这:

sumEuler = sum . map_euler . mkList

仅仅意味着 sumEuler 是这些函数的未应用的组合:

sumEuler = \x -> sum (map_euler (mkList x))

Dot Operator in Haskell

I'm trying to understand what the dot operator is doing in this Haskell code:

sumEuler = sum . (map euler) . mkList

Short answer

Equivalent code without dots, that is just

sumEuler = \x -> sum ((map euler) (mkList x))

or without the lambda

sumEuler x = sum ((map euler) (mkList x))

because the dot (.) indicates function composition.

Longer answer

First, let's simplify the partial application of euler to map:

map_euler = map euler
sumEuler = sum . map_euler . mkList

Now we just have the dots. What is indicated by these dots?

From the source:

(.)    :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)

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

(f ∘ g)(x)

which can be read "f composed with g".

So in Haskell, f ∘ g, or f composed with g, can be written:

f . g

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:

sumEuler = sum . map_euler . mkList

just means that sumEuler is an unapplied composition of those functions:

sumEuler = \x -> sum (map_euler (mkList x))
饮湿 2024-07-21 18:23:11

点运算符将左侧函数 (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 of mkList to (map euler), and then passing the result of that to sum.
This site has a good introduction to several of the concepts.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文