是否可以为F#元组编写扩展方法?例如,添加实例方法.Item1和.Item2(如System.Tuple)相当于为2元组调用fst和snd?F#元组的扩展方法
回答
不完美,但我用这个。 (我从http://www.fssnip.net/6V借原代码,增加了小的修改。)
[<AutoOpen>]
module TupleExtensions =
type System.Tuple with
static member Item1(t) = let (x,_) = t in x
static member Item1(t) = let (x,_,_) = t in x
static member Item1(t) = let (x,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_,_,_) = t in x
static member Item2(t) = let (_,x) = t in x
static member Item2(t) = let (_,x,_) = t in x
static member Item2(t) = let (_,x,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_,_,_) = t in x
static member Item3(t) = let (_,_,x) = t in x
static member Item3(t) = let (_,_,x,_) = t in x
static member Item3(t) = let (_,_,x,_,_) = t in x
static member Item3(t) = let (_,_,x,_,_,_) = t in x
static member Item3(t) = let (_,_,x,_,_,_,_) = t in x
static member Item4(t) = let (_,_,_,x) = t in x
static member Item4(t) = let (_,_,_,x,_) = t in x
static member Item4(t) = let (_,_,_,x,_,_) = t in x
static member Item4(t) = let (_,_,_,x,_,_,_) = t in x
static member Item5(t) = let (_,_,_,_,x) = t in x
static member Item5(t) = let (_,_,_,_,x,_) = t in x
static member Item5(t) = let (_,_,_,_,x,_,_) = t in x
static member Item6(t) = let (_,_,_,_,_,x) = t in x
static member Item6(t) = let (_,_,_,_,_,x,_) = t in x
static member Item7(t) = let (_,_,_,_,_,_,x) = t in x
如何使用它:
let t = (1, 2, 3)
let item1 = Tuple.Item1(t)
Tuple.Item1这里定义有超过FST的优势:它是多态的项目数。一旦我们使用这些扩展方法编写使用n元组的函数,我们可以在不修改函数体的情况下将其扩展为n + 1元组。相反,我们必须修改参数类型声明。这是更轻松。
在F#中内部表示(2元素)元组的System.Tuple<'T1, 'T2>
类型实际上已经具有属性Item1
和Item2
,但它们被F#编译器隐藏。向元组添加扩展成员的一个显而易见的方法并不能解决问题,所以我不希望这样做(但可能有一些我不知道的解决方法)。
一般来说,我认为模式匹配比诸如Item1
,Item2
等成员更可取(并且C#3.0程序员在处理元组时通常要求模式匹配支持:-))。
原因是模式匹配强制你命名的东西。比较这两个代码段:
let (width, height) = tuple
width * height
和使用性能的版本:
tuple.Item1 * tuple.Item2
第二个是一个位短,但绝对少可读。
我想,你所要求的不是很有功能的方式。您可以使用实例方法创建自己的类型,但同时您正在失去函数式编程的许多方面,例如模式匹配。
除此之外,一个DU似乎是要走的路:
type MyTuple<'T, 'U> =
| MyTuple of 'T * 'U
with
member this.MyItem1 = match this with | MyTuple(x,y) -> x
member this.MyItem2 = match this with | MyTuple(x,y) -> y
let x = MyTuple(42, "foo")
let y1 = x.MyItem1 // 42
let y2 = x.MyItem2 // "foo"
由于@Tomas Petricek指出,因为他们在System.Tuple<'T1, 'T2>
已经存在,所以无法命名的属性Item1
和Item2
。试图这样做将导致一个错误:
error FS2014: A problem occurred writing the binary [filename]: Error in pass2 for type [...], error: Error in pass2 for type MyTuple`2, error: duplicate entry 'Item1' in property table
您也可以使用fst
和snd
功能得到你想要的值(显然写自己的第三,第四,等等。如果你真的想) 。
解决方法是使用C#样式扩展定义。
这会工作得很好:
open System.Runtime.CompilerServices
[<Extension>]
type TupleExtensions() =
[<Extension>] static member First((a,b)) = a
[<Extension>] static member First((a,b,c)) = a
let x = (1,2).First()
let y = (1,2,3).First()
但我同意,这不是一个好主意,通过方法来访问一个元组的元素,模式匹配是最好的方式。
- 1. F#和PLINQ扩展方法
- 2. 是否有可能为F#元组创建扩展方法
- 3. 扩展方法定义/调用在F#
- 4. 如何创建扩展方法(F#)?
- 5. 组织扩展方法
- 6. 分组扩展方法
- 7. F#模块扩展与类型扩展
- 8. 扩展方法
- 9. 扩展方法
- 10. 的扩展方法
- 11. F#将活动模式与扩展元组匹配
- 12. f的反应式扩展#
- 13. 可扩展枚举的扩展方法
- 14. 扩展类成员的扩展方法?
- 15. 使用扩展方法的扩展类
- 16. 使用扩展方法覆盖F#中的静态属性
- 17. 使用F#函数类型的扩展方法
- 18. 是否存在与此C#扩展方法等效的F#?
- 19. F#的一种扩展方法,参考另一
- 20. 无法在F#中扩展运算符?
- 21. 单元测试UrlHelper扩展方法
- 22. AutoMapper展开扩展方法
- 23. 如何分组扩展方法?
- 24. TypeScript - 数组排序扩展方法
- 25. 如何组织Kotlin扩展方法
- 26. 扩展方法扩展静态类
- 27. NativeScript扩展方法
- 28. 扩展方法ConvertAll
- 29. C#扩展方法
- 30. XElement.Elements()扩展方法?
感谢Tomas。我同意,但是如果有解决方法,我仍然对此感兴趣(而不是像下面的bytebuster建议的那样采用新的类型)? – mpeac