7

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

谢谢。

4

1 回答 1

13

删除与List.reduce (>>)更改类型的行showRainbow,因此您会得到不是函数的东西,因此流水线操作员不能将其defaultLabel作为参数调用。

在原始程序中,类型showRainbow是一个将一个CoolLabel变成另一个的函数:

val showRainbow : (CoolLabel -> CoolLabel)

如果删除该行,您将获得一个函数列表

val showRainbow : (CoolLabel -> CoolLabel) list 

这个例子并没有以微不足道的方式使用函数,所以让我解释一下究竟发生了什么。我们从rainbow颜色列表开始。接下来,rainbow |> List.map setLabel颜色列表转换为函数列表。您可以将其解读为:

rainbow |> List.map (fun color -> setLabel color)

但是,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";}
于 2013-09-01T01:14:35.293 回答