玩弄F#,我对以下行为感到困惑。当List.reduce (>>)
被注释掉时,会出现错误
defaultLabel |> showRainbow
----------------^^^^^^^^^^^
This expression was expected to have type
CoolLabel -> 'a
but here has type
(CoolLabel -> CoolLabel) list
在此示例中从http://fsharpforfunandprofit.com/posts/conciseness-functions-as-building-blocks/:
归结// create an underlying type
type CoolLabel = {
label : string;
}
let defaultLabel =
{label="";}
let setLabel msg label =
{label with CoolLabel.label = msg}
let rainbow =
["red";"orange";"yellow";"green";"blue";"indigo";"violet"]
let showRainbow =
rainbow
|> List.map setLabel
|> List.reduce (>>)
// test the showRainbow function
defaultLabel |> showRainbow
删除List.reduce (>>)
后,我认为showRainbow应该返回一个CoolLabel列表,编译器会很酷。
编辑 - > (忽略这句话,因为下面的答案改变了我的理解。):“另外,我得到List.reduce(>>)将从列表中返回最后一个CoolLabel。”
感谢。
答案 0 :(得分:13)
使用List.reduce (>>)
删除行会更改showRainbow
的类型,因此您获得的功能不是函数,因此流水线操作符无法以defaultLabel
作为参数调用它。 / p>
在原始程序中,showRainbow
的类型是将CoolLabel
转换为另一个val showRainbow : (CoolLabel -> CoolLabel)
的函数:
val showRainbow : (CoolLabel -> CoolLabel) list
如果删除该行,则会获得列表的功能:
rainbow
这个例子并没有以微不足道的方式使用函数,所以让我解释一下实际上是什么。我们从rainbow |> List.map setLabel
开始,这是一个颜色列表。接下来,rainbow |> List.map (fun color -> setLabel color)
将 colors 列表转换为 functions 列表。您可以将其读作:
setLabel
但是,CoolLabel
需要两个参数。这里我们只指定第一个,因此结果是一个期望List.reduce (>>)
的函数,并将其颜色更改为彩虹的当前颜色。
获得函数列表后,let resultingFunction input =
setLabel "violet" (setLabel "indigo" (setLabel "blue" ( ... (input)))))
组成它们 - 它会构建一个新函数,在它接收的输入上调用所有函数。所以结果基本上是一个函数:
defaultLabel
现在你可以看到为什么这会返回带紫色的标签 - 它会将setLabel
的颜色更改为红色,然后变为橙色,然后变为黄色等,最后变为靛蓝色,然后变为紫色!
如果您更改setLabel
以便它不会忽略原始颜色,但可能会将它们组合在一起(通过附加字符串),那么您将看到如何在所有颜色上调用let setLabel msg label =
{ label with CoolLabel.label = label.label + " " + msg }
函数:
> defaultLabel |> showRainbow;;
val it : CoolLabel = {label = " red orange yellow green blue indigo violet";}
结果将是:
{{1}}