有没有办法在保持流畅的管道语法的同时执行比较?
例如,我想这样做:
(positions , source) ||> jump target
|> List.length = positions.Length ||
positions.Length - 1
Run Code Online (Sandbox Code Playgroud)
但相反,我觉得我必须这样做:
let updatedPositions = (positions , source) ||> jump target
// Return result
updatedPositions |> List.length = positions.Length ||
updatedPositions |> List.length = positions.Length - 1
Run Code Online (Sandbox Code Playgroud)
附录:
[<Property(QuietOnSuccess = true, MaxTest=1000)>]
let ``Attempted checker jump results in zero or one distinct checkers removed`` () =
// Setup
gen {
let! source = Arb.generate<Piece>
let! target = Arb.generate<Piece>
let! otherPositions = Arb.generate<Space list>
let! positions = Occupied source :: Occupied target
:: otherPositions
|> Gen.shuffle
return source , target, positions |> Seq.distinct
|> Seq.toList }
|> Arb.fromGen
// Test
|> Prop.forAll
<| fun (source , target, positions) ->
(positions , source) ||> jump target
|> List.length = positions.Length ||
List.length = positions.Length - 1 // Wish I could do this...
Run Code Online (Sandbox Code Playgroud)
@ildjarn在评论中发布的解决方案是您问题的答案.
但是,我个人不会这样做.当您对捕获"代码的主要数据"的内容执行一系列转换时,管道非常有用.管道有一个输入和一个输出,这很好地捕获了这个:
let output =
input
|> firstTransformation
|> secondTransformation
Run Code Online (Sandbox Code Playgroud)
Pipe可以在许多其他场景中使用(毕竟,它只是一个运算符),但我认为在其他场景中使用它并不会使F#代码更具可读性.将管道仅用于"主要数据"的好处是,快速浏览一下代码可以显示重要操作的位置.
这也是我不太热衷的部分原因||>- 它有助于类型推断,fold但除此之外,它给人一种假象,即当一个函数实际上需要多个同等重要的输入时,它有一个"主输入".所以在你的例子中,我会写:
let updatedPositions = jump target positions source
updatedPositions.Length = positions.Length ||
updatedPositions.Length = positions.Length - 1
Run Code Online (Sandbox Code Playgroud)
我认为这更好地对应于代码背后的逻辑 - 传递两个东西jump并检查结果的两个属性 - 而不是以下管道版本:
(positions, source)
||> jump target
|> fun updatedPositions ->
updatedPositions.Length = positions.Length ||
updatedPositions.Length = positions.Length - 1
Run Code Online (Sandbox Code Playgroud)
版本let更短,更简单.阅读第二篇文章时,你必须解压得很多才能弄清楚发生了什么.