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

Sno*_*rex 7 f#

玩弄F#,我对以下行为感到困惑.何时List.reduce (>>)被注释掉,有错误

defaultLabel |> showRainbow
----------------^^^^^^^^^^^
This expression was expected to have type
    CoolLabel -> 'a    
but here has type
    (CoolLabel -> CoolLabel) list
Run Code Online (Sandbox Code Playgroud)

在这个例子中,来自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
Run Code Online (Sandbox Code Playgroud)

什么时候List.reduce (>>)删除,我认为showRainbow应该返回一个CoolLabel列表,编译器会很酷.

编辑 - >(忽略这句话,因为下面的答案改变了我的理解.):"顺便说一句,我得到的List.reduce(>>)会从列表中返回最后一个CoolLabel."

谢谢.

Tom*_*cek 13

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

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

val showRainbow : (CoolLabel -> CoolLabel)
Run Code Online (Sandbox Code Playgroud)

如果删除线,你会得到一个列表的功能:

val showRainbow : (CoolLabel -> CoolLabel) list 
Run Code Online (Sandbox Code Playgroud)

这个例子不是以微不足道的方式使用函数,所以让我解释一下实际上正在发生什么.我们从rainbow哪个颜色列表开始.接下来,rainbow |> List.map setLabel颜色列表转换为函数列表.你可以这样读:

rainbow |> List.map (fun color -> setLabel color)
Run Code Online (Sandbox Code Playgroud)

但是,setLabel两个论点.这里我们只指定第一个,因此结果是一个函数,它期望CoolLabel并将其颜色更改为彩虹的当前颜色.

一旦你有了函数列表,就List.reduce (>>)组成它们 - 它构建一个新函数,在它接收的输入上调用它们的所有函数.所以结果基本上是一个功能:

let resultingFunction input = 
  setLabel "violet" (setLabel "indigo" (setLabel "blue" ( ... (input)))))
Run Code Online (Sandbox Code Playgroud)

现在你可以看到为什么这会返回一个紫罗兰色的标签 - 它将颜色defaultLabel变为红色,然后变为橙色,然后变为黄色等,最后变为靛蓝色,然后变为紫色!

如果你改变setLabel它不会忽略原始颜色,但也许组合它们(通过附加字符串),那么你将看到如何setLabel在所有颜色上调用该函数:

let setLabel msg label = 
  { label with CoolLabel.label = label.label + " " + msg }
Run Code Online (Sandbox Code Playgroud)

结果将是:

> defaultLabel |> showRainbow;;
val it : CoolLabel = {label = " red orange yellow green blue indigo violet";}
Run Code Online (Sandbox Code Playgroud)