有没有办法将两个参数传递给 Elm 中的函数?
Is there a way to pipe two arguments to a function in Elm?
具有以下功能:
f : Int -> Int -> Int
f a b =
a + b
有没有办法同时通过管道传输 a 和 b?
我只知道到这里,但我想知道是否有办法去掉括号:
main =
1 |> (2 |> f) |> toString |> text
虽然它可能不能让你满意,但一个简单的可能性是:
(1, 2) |> uncurry f
我想不会。我从来没有见过它。之所以如此不可能,是因为从技术上讲,所有 elm 函数都只接受一个参数。但是这样的事情呢?
add 1 2 3
好吧,Elm 实际上是 curry 函数,return 是第一个参数之后的匿名函数,第二个参数是第二个参数,return 是第三个参数。如果你想知道为什么类型注释看起来像在多个参数和 return 语句之间没有分隔......
add : Int -> Int -> Int
...那是因为没有!
不要为了管道而管道。说 1 |> f 2 |> toString |> text
比你的例子中的要清晰得多。通过管道传递的参数通常是数据结构,因为按照惯例它总是最后一个参数。让我们看一个更现实的例子:
"40"
|> String.toInt
|> Maybe.map (\n -> n + 2)
|> Maybe.withDefault 2
直接参数(lambda,2
)影响操作,而数据结构(链的一部分的 Maybe Int
)通过管道传输。对比度:Maybe.withDefault 2 (Maybe.map (\n -> n + 2) (String.toInt "40"))
。这个丑陋的版本甚至更快,因为编译器优化了管道。
如果以这种方式通过管道传输数据结构的转换,则无需通过管道传输两个项目。
您可以像这样实现类似的 流程:
1 :: 2 :: [] |> List.foldl f 0 |> toString |> text
想法是使用 ::
创建包含参数的 List
。然后,使用 foldl
将函数 f
应用于参数。
当然,语法中有很多多余的项目:空List
和foldl
需要的起始值。继续您的示例函数,您可以使用合成来 隐藏 起始值:
let
g = List.foldl f 0
in
1 :: 2 :: [] |> g |> toString |> text
缺点是您仍然需要处理一个起始值,您可能希望它只是列表的开头(例如 1)。但是,如果您尝试使用列表的头部作为起始值,您会遇到另一个问题:
如果没有起始值(空列表),则 fold 不能 return 任何东西,所有 Elm 函数都有一个 return 值。
无论如何,希望这种方法能有所帮助。
|>
管道首先计算左侧,这是您想要的,并将第一个参数应用于第二个,这不是您想要的。
<|
管道首先计算右侧,这不是您想要的,然后将第二个参数应用于第一个,这不是您想要的。
您可以使用反转函数应用程序的 lambda 来绕过它。像这样
add a b = a + b
add
|> \f -> f 2
|> \f -> f 3
-- outcome: 5
或者你可以写一个辅助函数
invert v f = f v
add
|> invert 2
|> invert 3
具有以下功能:
f : Int -> Int -> Int
f a b =
a + b
有没有办法同时通过管道传输 a 和 b?
我只知道到这里,但我想知道是否有办法去掉括号:
main =
1 |> (2 |> f) |> toString |> text
虽然它可能不能让你满意,但一个简单的可能性是:
(1, 2) |> uncurry f
我想不会。我从来没有见过它。之所以如此不可能,是因为从技术上讲,所有 elm 函数都只接受一个参数。但是这样的事情呢?
add 1 2 3
好吧,Elm 实际上是 curry 函数,return 是第一个参数之后的匿名函数,第二个参数是第二个参数,return 是第三个参数。如果你想知道为什么类型注释看起来像在多个参数和 return 语句之间没有分隔......
add : Int -> Int -> Int
...那是因为没有!
不要为了管道而管道。说 1 |> f 2 |> toString |> text
比你的例子中的要清晰得多。通过管道传递的参数通常是数据结构,因为按照惯例它总是最后一个参数。让我们看一个更现实的例子:
"40"
|> String.toInt
|> Maybe.map (\n -> n + 2)
|> Maybe.withDefault 2
直接参数(lambda,2
)影响操作,而数据结构(链的一部分的 Maybe Int
)通过管道传输。对比度:Maybe.withDefault 2 (Maybe.map (\n -> n + 2) (String.toInt "40"))
。这个丑陋的版本甚至更快,因为编译器优化了管道。
如果以这种方式通过管道传输数据结构的转换,则无需通过管道传输两个项目。
您可以像这样实现类似的 流程:
1 :: 2 :: [] |> List.foldl f 0 |> toString |> text
想法是使用 ::
创建包含参数的 List
。然后,使用 foldl
将函数 f
应用于参数。
当然,语法中有很多多余的项目:空List
和foldl
需要的起始值。继续您的示例函数,您可以使用合成来 隐藏 起始值:
let
g = List.foldl f 0
in
1 :: 2 :: [] |> g |> toString |> text
缺点是您仍然需要处理一个起始值,您可能希望它只是列表的开头(例如 1)。但是,如果您尝试使用列表的头部作为起始值,您会遇到另一个问题:
如果没有起始值(空列表),则 fold 不能 return 任何东西,所有 Elm 函数都有一个 return 值。
无论如何,希望这种方法能有所帮助。
|>
管道首先计算左侧,这是您想要的,并将第一个参数应用于第二个,这不是您想要的。
<|
管道首先计算右侧,这不是您想要的,然后将第二个参数应用于第一个,这不是您想要的。
您可以使用反转函数应用程序的 lambda 来绕过它。像这样
add a b = a + b
add
|> \f -> f 2
|> \f -> f 3
-- outcome: 5
或者你可以写一个辅助函数
invert v f = f v
add
|> invert 2
|> invert 3