为什么在这个新手示例中需要List.reduce?

时间:2013-09-01 01:04:20

标签: f#

玩弄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。”

感谢。

1 个答案:

答案 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}}
相关问题