.net F#-不理解函数的组成(将get files函数转换为get replicate files函数)
这是我的问题。。。我不明白为什么这对我不起作用:) 更具体地说,我有一个获取文件功能(这不是问题,但欢迎反馈): 这给了我一个Seq.groupBy LengthAndExtension上的编译错误 错误在于类型“b->seq”与类型“seq正向合成(.net F#-不理解函数的组成(将get files函数转换为get replicate files函数),.net,f#,functional-programming,composition,.net,F#,Functional Programming,Composition,这是我的问题。。。我不明白为什么这对我不起作用:) 更具体地说,我有一个获取文件功能(这不是问题,但欢迎反馈): 这给了我一个Seq.groupBy LengthAndExtension上的编译错误 错误在于类型“b->seq”与类型“seq正向合成(>)不兼容。它创建了一个新函数,将第一个函数的输出作为输入传递给第二个函数 签名揭示了问题:(>>):('T1->'T2)->('T2->'T3)->'T1->'T3 它接受两个函数,每个函数接受一个参数。但是GetFiles需要两个参数。一个快速
>
)不兼容。它创建了一个新函数,将第一个函数的输出作为输入传递给第二个函数
签名揭示了问题:(>>):('T1->'T2)->('T2->'T3)->'T1->'T3
它接受两个函数,每个函数接受一个参数。但是
GetFiles
需要两个参数。一个快速的解决方案是更改GetFiles
以获取元组:让GetFiles(dir,extlist)=……
使用函数组合>,我们有:(f>>g)x=g(f(x))
。这意味着我们首先对输入应用f
,然后对输出应用g
使用函数组合的一种简单方法是先使用管道编写函数,然后再对其进行重构。我通常以x>f1>f2>fn
,删除输入x
,并将管道(|>
)更改为函数合成(>
),以具有正确的合成函数f1>>f2>…>>fn
。但是,在您的示例中并不明显:
let GetDuplicateFiles(dir, extlist) =
//...
GetFiles dir extlist
|> Seq.groupBy LengthAndExtension
|> Seq.filter GroupSizeGreaterThanOne
|> Seq.collect groups
|> Seq.groupBy content
|> Seq.filter GroupSizeGreaterThanOne
|> Seq.collect groups
如果将GetFiles
从当前形式的GetFiles dir extlist
更改为元组形式的GetFiles(dir,extlist)
,则可以轻松应用上述技巧来使用函数组合
另外,您可以更改Seq.filter…>>顺序收集
至顺序选择…>>Seq.concat
要在序列中保存一次遍历,请执行以下操作:
let GetDuplicateFiles =
//...
// (dir, extlist)
// |>
GetFiles
>> Seq.groupBy LengthAndExtension
>> Seq.choose GroupSizeGreaterThanOne
>> Seq.concat
>> Seq.groupBy content
>> Seq.choose GroupSizeGreaterThanOne
>> Seq.concat
GroupSizeGreaterThanOne
功能略有更改:
let GroupSizeGreaterThanOne (_, values) =
if Seq.length values > 1 then Some values else None
这是否意味着F#函数组合和数学组合略有不同,而让F#模拟数学的方法是将n个输入包装成一个元组?很好,但还行。我的代码现在可以用了,谢谢。原因是函数不能有多个返回值。元组是实现这一点的方法。我认为您的代码更干净,但遍历保存在哪里?Seq.collect
基本上是Seq.map
后面是Seq.concat
。通过保存遍历,我的意思是您可以删除不必要的Seq.map
。Seq.collect不是与序列的一元绑定相同吗?另外,Seq.collect、Seq.map、Seq.concat是否都很懒,这意味着我不保存序列本身的遍历,而是在堆栈上保存一个额外的调用?
let GetDuplicateFiles =
//...
// (dir, extlist)
// |>
GetFiles
>> Seq.groupBy LengthAndExtension
>> Seq.choose GroupSizeGreaterThanOne
>> Seq.concat
>> Seq.groupBy content
>> Seq.choose GroupSizeGreaterThanOne
>> Seq.concat
let GroupSizeGreaterThanOne (_, values) =
if Seq.length values > 1 then Some values else None