<< http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Basics#%3C%3C是一个函数组合运算符,在核心库中定义Basics http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Basics。 Basics 中的所有功能均不合格地导入到 Elm 项目中。
Elm 的类型系统
让我们回顾一下 Elm 类型系统的基础知识。
Elm is 静态类型 http://elm-lang.org/guide/model-the-problem#contracts。这意味着在 Elm 中每个变量或函数都有一个类型,并且这个类型永远不会改变。 Elm 中的类型示例有:
Int
String
Maybe Bool
{ name : String, age : Int }
Int -> Int
-
Int -> String -> Maybe Char
.
静态类型意味着编译器确保所有函数和变量的类型在编译期间都是正确的,因此不会出现运行时类型错误。换句话说,你永远不会有类型的函数String -> String
接收或返回Int
,允许这样做的代码甚至无法编译。
您还可以通过替换具体类型来使函数具有多态性,例如String
or Maybe Int
带有类型变量,它是任意小写字符串,例如a
。许多 Elm 核心函数都是类型多态的,例如List.isEmpty http://package.elm-lang.org/packages/elm-lang/core/2.1.0/List#isEmpty有类型List a -> Bool
。这需要一个List
某种类型并返回类型的值Bool
.
如果您再次看到相同类型的变量,则该类型变量的实例必须是相同类型的。例如List.reverse http://package.elm-lang.org/packages/elm-lang/core/2.1.0/List#reverse有类型List a -> List a
。所以如果你申请List.reverse
到一个整数列表(即具有类型的东西List Int
), it will返回一个整数列表。这样的函数不可能接受整数列表,但返回字符串列表。这是由编译器保证的。
Elm 中的所有函数都是curried https://stackoverflow.com/a/36321/596361默认情况下。这意味着,如果您有一个包含 2 个参数的函数,它将转换为一个包含 1 个参数的函数,并返回一个包含 1 个参数的函数。这就是为什么 Elm 的函数应用语法与其他语言(如 Java、C++、C#、Python 等)中的函数应用如此不同。没有理由编写someFunction(arg1, arg2)
,当你可以写someFunction arg1 arg2
。为什么?因为现实中someFunction arg1 arg2
实际上是((someFunction arg1) arg2)
.
柯里化使得部分应用 https://stackoverflow.com/q/218025/596361可能的。假设您想部分申请List.member http://package.elm-lang.org/packages/elm-lang/core/2.1.0/List#member. List.member
有一个类型a -> List a -> Bool
。我们可以将类型读作“List.member
接受 2 个参数,类型为a
并输入List a
”。但我们也可以将类型读作“List.member
接受 1 个类型参数a
。它返回一个类型的函数List a -> Bool
”。因此我们可以创建一个函数isOneMemberOf = List.member 1
,其类型为List Int -> Bool
.
这意味着->
在函数的类型注释中是右关联的。换句话说,a -> List a -> Bool
是相同的a -> (List a -> Bool)
.
中缀和前缀表示法
Any 中缀运算符 http://elm-lang.org/docs/syntax#infix-operators实际上是一个普通的幕后函数。只是当函数名称仅由非字母数字符号(例如 $、
但你仍然可以放置一个二元运算符,例如+
在 2 个参数前面,将其括在括号中,因此下面的 2 个函数应用程序是等效的:
2 + 3 -- returns 5
(+) 2 3 -- returns 5, just like the previous one
中缀运算符只是普通函数。他们没有什么特别的。您可以像任何其他函数一样部分应用它们:
addTwo : Int -> Int
addTwo = (+) 2
addTwo 3 -- returns 5
功能组成
(<<) http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Basics#%3C%3C是一个函数组合运算符,在核心库中定义Basics http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Basics。所有基础函数都被无条件导入到 Elm 项目中,这意味着您不必编写import Basics exposing (..)
,默认情况下已经完成了。
所以就像任何其他运营商一样,(<<)
和其他函数一样,它只是一个函数。它的类型是什么?
(<<) : (b -> c) -> (a -> b) -> a -> c
Because ->
是右结合的,这相当于:
(<<) : (b -> c) -> (a -> b) -> (a -> c)
换句话说,(<<)
需要 2 个类型的函数b -> c
and a -> b
分别,并返回一个类型的函数a -> c
。它将 2 个函数合二为一。这是如何运作的?为了简单起见,让我们看一个人为的例子。假设我们有两个简单的函数:
addOne = (+) 1
multTwo = (*) 2
假设我们没有(+)
, only addOne
,我们如何创建一个加 3 而不是 1 的函数?很简单,我们就组成addOne
一起3次:
addThree : Int -> Int
addThree = addOne << addOne << addOne
如果我们想要创建一个加 2 然后乘以 4 的函数该怎么办?
ourFunction : Int -> Int
ourFunction = multTwo << multTwo << addOne << addOne
(<<)
从右到左组合函数。但上面的例子很简单,因为所有类型都是相同的。我们如何找到列表中所有偶数立方体的和?
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
(>>)
是相同的函数,但参数翻转,因此我们可以从左到右编写相同的组合:
ourFunction2 = map cube >> filter isEven >> List.sum
Recap
当你看到类似的东西时h << g << f
,那么你就知道f
, g
, h
是函数。当这个构造h << g << f
应用于一个值x
,那么你就知道:
- 榆树首先适用
f
to x
- 然后应用
g
到上一步的结果
- 然后应用
h
到上一步的结果
所以(negate << (*) 10 << sqrt) 25
equals -50.0
,因为首先对 25 求平方根,得到 5,然后将 5 乘以 10,得到 50,然后对 50 求反,得到 -50。
为什么
Elm 0.13 之前(参见公告 http://elm-lang.org/blog/announce/0.13) 函数复合运算符是(.)
,其行为与当前的相同(<<)
. (<<)
在 Elm 0.13 中采用了 F# 语言(请参阅Github问题 https://github.com/elm-lang/elm-lang.org/issues/158)。还添加了 Elm 0.13(>>)
相当于flip (<<)
, and (<|) http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Basics#%3C%7C作为函数应用运算符的替代品($)
, and (|>) http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Basics#%7C%3E相当于flip (<|)
.
中缀函数调用
您可能想知道是否可以将普通的字母数字函数名称转换为中缀二元运算符。在 Elm 0.18 之前,您可以使用反引号来使函数中缀,因此下面的 2 是等效的:
max 1 2 -- returns 2
1 `max` 2 -- returns 2
榆木 0.18删除了这个功能 https://github.com/elm-lang/elm-platform/blob/master/upgrade-docs/0.18.md#backticks-and-andthen。你不能再用 Elm 做到这一点,但是像这样的语言Haskell http://haskell.org and 纯脚本 http://purescript.org仍然有它。