Elm中的<<运算符是什么意思? [英] What does the `<<` operator mean in elm?

查看:99
本文介绍了Elm中的<<运算符是什么意思?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下摘自 Elm表格示例的第122行中的代码中,<< 运算符是什么意思?

In the following code taken from Elm Form Example, line 122, what does the << operator mean?

Field.field Field.defaultStyle (Signal.send updateChan << toUpdate) "" content

Elm语法参考中找到。

这是否意味着在字段更改时,不发送其内容 updateChan ,而是发送 toUpdate updateChan

Does it mean, when the field changes, instead of sending its content to updateChan, send toUpdate to updateChan?

推荐答案

<< 是一个函数组合运算符,在核心库 Basics 。来自Basics的所有功能均不合格地导入Elm项目。

<< is a function composition operator, defined in core library Basics. All functions from Basics are imported into Elm projects unqualified.

让我们回顾Elm类型的基础知识系统。

Let's recall basics of Elm type system.

Elm是静态输入。这意味着在Elm中,每个变量或函数都有一个类型,并且该类型永远不会改变。榆木类型的示例如下:

Elm is statically typed. This means that in Elm every variable or function has a type, and this type never changes. Examples of types in Elm are:


  • Int

  • 字符串

  • 也许是布尔人

  • {名称:字符串,年龄:整数}

  • Int-> Int

  • Int->字符串->也许是Char

  • Int
  • String
  • Maybe Bool
  • { name : String, age : Int }
  • Int -> Int
  • Int -> String -> Maybe Char.

静态类型表示编译器确保所有函数和变量的类型在编译期间都是正确的,这样您就不会出现运行时类型错误。换句话说,您永远不会拥有 String->类型的函数。字符串接收或返回 Int ,允许该代码甚至无法编译的代码。

Static typing means that compiler ensures types of all functions and variables are correct during compilation, so you don't have runtime type errors. In other words, you'll never have a function of type String -> String receiving or returning Int, code that allows this won't even compile.

您还可以通过将具体类型(例如 String Maybe Int )替换为类型变量,使函数变为多态,这是一个任意的小写字符串,例如 a 。许多Elm核心功能都是多态的,例如 List.isEmpty 的类型为 List a->布尔。它需要某种类型的 List 并返回类型为 Bool 的值。

You can also make your functions polymorphic by replacing a concrete type such as String or Maybe Int with a type variable, which is an arbitrary lowercase string, such as a. Many Elm core functions are type polymorphic, for example List.isEmpty has the type List a -> Bool. It takes a List of some type and returns a value of type Bool.

如果再次看到相同类型的变量,则此类型变量的实例必须为相同类型。例如 List.reverse 的类型为 List a->列出一个。因此,如果将 List.reverse 应用于整数列表(即应用于类型为 List Int 的对象),它将返回一个整数列表。这样的函数无法获取整数列表,而只能返回字符串列表。

If you see the same type variable again, then instances of this type variable must be of same type. For example List.reverse has type List a -> List a. So if you apply List.reverse to a list of integers (i.e. to something that has type List Int), it will return a list of integers back. No way such function can take a list of integers, but return a list of strings. This is guaranteed by the compiler.

Elm中的所有函数均已咖喱默认情况下。这意味着,如果您具有2个参数的函数,则它将转换为1个参数的函数,并返回1个参数的函数。这就是为什么Elm的函数应用程序语法与Java,C ++,C#,Python等其他语言的函数应用程序语法如此不同的原因。没有理由编写 someFunction(arg1,arg2),当您可以编写 someFunction arg1 arg2 时。为什么?因为实际上 someFunction arg1 arg2 实际上是(((someFunction arg1)arg2)

All functions in Elm are curried by default. This means that if you have a function of 2 arguments, it is transformed into a function of 1 argument that returns a function of 1 argument. That's why you function application syntax of Elm is so different from function application in other languages such as Java, C++, C#, Python, etc. There's no reason to write someFunction(arg1, arg2), when you can write someFunction arg1 arg2. Why? Because in reality someFunction arg1 arg2 is actually ((someFunction arg1) arg2).

通过固化,可以实现部分应用。假设您要部分应用 List.member List.member 具有类型 a->列出->布尔。我们可以将类型读取为 List.member 接受2个参数,类型分别为 a 列出一个。但是我们也可以将类型读取为 List.member 接受1个类型为 a 的参数。它返回类型为 List a->的函数。布尔。因此,我们可以创建一个函数 isOneMemberOf = List.member 1 ,该函数的类型为 List Int->布尔

Currying makes partial application possible. Suppose you want to partially apply List.member. List.member has a type a -> List a -> Bool. We can read the type as "List.member takes 2 arguments, of type a and type List a". But we can also read the type as "List.member takes 1 argument of type a. It returns a function of type List a -> Bool". Therefore we can create a function isOneMemberOf = List.member 1, which will have the type List Int -> Bool.

这意味着函数类型注释中的-> 是正确的-联想。换句话说, a->列出->布尔 a->相同。 (列出a-> Bool)

This means that -> in type annotations of functions is right-associative. In other words, a -> List a -> Bool is the same as a -> (List a -> Bool).

任何中缀运算符实际上都是幕后的普通功能。只是当函数名称仅由非字母数字符号(例如$,< |,<<等)组成时,它才放在2个参数之间,而不是放在它们的前面(如普通函数)。

Any infix operator is actually an ordinary function behind the curtains. It's just when a function name consists solely of non-alphanumeric symbols (such as $, <|, <<, etc), it is placed between 2 arguments, not in front of them (like ordinary functions).

但是您仍然可以在2个参数前加上 + 之类的二进制运算符,方法是将其括在括号中,因此以下两个函数应用程序是等效的:

But you still can put a binary operator like + in front of the 2 arguments, by enclosing it in parentheses, so the 2 function applications below are equivalent:

2 + 3 -- returns 5
(+) 2 3 -- returns 5, just like the previous one

中缀运算符只是普通函数一样。它们没有什么特别的。您可以像应用任何其他函数一样部分地应用它们:

Infix operators are just ordinary functions. There's nothing special about them. You can partially apply them just like any other function:

addTwo : Int -> Int
addTwo = (+) 2

addTwo 3 -- returns 5



功能组成



(<<) 是在核心库 基础 。所有来自基础的功能都可以不加限制地导入Elm项目,这意味着您不必编写 import基础暴露(..),默认情况下已完成。

Function composition

(<<) is a function composition operator, defined in core library Basics. All functions from basics are imported into Elm projects unqualified, meaning you don't have to write import Basics exposing (..), it is already done by default.

因此,与任何其他运算符一样,(<<)只是一个函数,与其他任何运算符一样。它的类型是什么?

So just like any other operator, (<<) is just a function, like any other. What is its type?

(<<) : (b -> c) -> (a -> b) -> a -> c

因为-> 是正确的-关联,则等效于:

Because -> is right-associative, this is equivalent to:

(<<) : (b -> c) -> (a -> b) -> (a -> c)

换句话说,(<< ;)具有2个类型为 b->的函数; c a-> b ,并返回 a->类型的函数。 c 。它将2个功能组合为一个。这是如何运作的?为了简单起见,我们来看一个人为的示例。假设我们有2个简单的函数:

In other words, (<<) takes 2 functions of types b -> c and a -> b respectively, and returns a function of type a -> c. It composes 2 functions into one. How does that work? Let's look at a contrived example for simplicity's sake. Suppose we have 2 simple functions:

addOne = (+) 1
multTwo = (*) 2

假设我们没有(+) addOne ,我们如何创建一个加3而不是1的函数?很简单,我们将 addOne 组成3次:

Suppose we don't have (+), only addOne, how would we create a function that adds 3, not 1? Very simple, we would compose addOne together 3 times:

addThree : Int -> Int
addThree = addOne << addOne << addOne

如果我们想创建一个将2加4的函数怎么办?

What if we want to create a function that adds 2, then multiples by 4?

ourFunction : Int -> Int
ourFunction = multTwo << multTwo << addOne << addOne

(<<)功能从右到左。但是上面的例子很简单,因为所有类型都是相同的。我们将如何找到列表中所有偶数立方体的总和?

(<<) composes functions from right-to-left. But the above example is simple, because all the types are the same. How would we find a sum of all even cubes of the list?

isEven : Int -> Bool
isEven n = n % 2 == 0

cube : Int -> Int
cube n = n * n * n

ourFunction2 : List Int -> Int
ourFunction2 = List.sum << filter isEven << map cube

(>>)是相同的函数,但参数已翻转,因此我们可以从左到右编写相同的组成:

(>>) is the same function, but with arguments flipped, so we can write the same composition from left to right instead:

ourFunction2 = map cube >> filter isEven >> List.sum



回顾



当您看到类似 h<< g<< f ,那么您知道 f g h 是函数。当此构造 h<< g<< f 应用于值 x ,那么您知道:

Recap

When you see something like h << g << f, then you know that f, g, h are functions. When this construct h << g << f is applied to a value x, then you know:


  • Elm首先将 f 应用于 x

  • 然后适用 g 到上一步的结果

  • 然后将 h 应用于结果

  • Elm first applies f to x
  • then applies g to the result of the previous step
  • then applies h to the result of the previous step

因此(否定<<(*)10<< sqrt) 25 等于 -50.0 ,因为您先取25的平方根得到5,然后将5乘以10得到50,然后得出否定50并得到-50。

Therefore (negate << (*) 10 << sqrt) 25 equals -50.0, because you first take a square root of 25 and get 5, then you multiply 5 by 10 and get 50, then you negate 50 and get -50.

在榆木0.13之前(请参见公告)函数组成运算符为(。),其行为与当前(<<)(<<)在Elm 0.13中从F#语言采用(请参阅 Github问题)。 Elm 0.13还添加了(>)等效于 flip(<<) (< |) 代替函数应用程序运算符($) ,和 ( |>) 等效于 flip(< |)

Before Elm 0.13 (see announcement) function composition operator was (.), and its behavior was identical to current (<<). (<<) was adopted in Elm 0.13 from F# language (see Github issue). Elm 0.13 also added (>>) as equivalent to flip (<<), and (<|) as replacement for function application operator ($), and (|>) as equivalent to flip (<|).

您可能想知道是否可以将普通的字母数字函数名称转换为中缀二进制运算符。在Elm 0.18之前,您将使用反引号对函数进行缀缀,因此以下2等效:

You might be wondering if you can turn an ordinary alphanumeric function name into an infix binary operator. Before Elm 0.18 you'd use backticks to make a function infix, so below 2 would be equivalent:

max 1 2 -- returns 2
1 `max` 2 -- returns 2

榆木0.18 删除了此功能。您再也无法在Elm中做到这一点,但是 Haskell PureScript 仍然拥有它。

Elm 0.18 removed this feature. You can't do it in Elm anymore, but languages like Haskell and PureScript still have it.

这篇关于Elm中的&lt;&lt;运算符是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆