简体   繁体   English

F#成员对元组的约束

[英]F# member constraints on tuples

I commonly have a "oh yeah" moment writing F# when I realize I need an extra value somewhere. 当我意识到我需要一个额外的价值时,我通常会写一个“哦耶”的时刻写F#。 This is generally easily done by adding another value to the tuple being passed around. 这通常可以通过向传递的元组添加另一个值来轻松完成。 However, this means that various maps/sorts/collects/etc. 但是,这意味着各种地图/排序/收集/等。 need updating, and in particular the functions fst/snd only work on tuples of length 2. 需要更新,特别是函数fst / snd只适用于长度为2的元组。

It's not a huge issue, but it's annoying enough during exploratory development that I though I'd write a helper to alleviate the annoyance: 这不是一个大问题,但在探索性开发过程中它很烦人,但我会写一个助手来减轻烦恼:

let inline get2 (t:^a) = (^a : (member get_Item2 : unit -> string) (t, ()))
let inline get2a (t:^a) = (^a : (member Item2 : string) t)

However, both versions do not work. 但是,这两个版本都不起作用。 The first, get2 , won't compile, with "Expected 1 expressions, got 2". 第一个, get2 ,将无法编译,“预期的1个表达式,得到2”。 The second, get2a , will compile, but subsequently can't be used on tuples: "The type '(int * string)' does not support any operators named 'get_Item2'". 第二个, get2a ,将编译,但随后不能在元组上使用:“类型'(int * string)'不支持任何名为'get_Item2'的运算符”。

Is there any way of doing this that doesn't involve lots of overloads? 有没有办法做到这一点,不涉及大量的重载? with noisy OverloadID annotations (annotations not required in F# 2.0) 带有嘈杂的 OverloadID注释 (F#2.0中不需要注释)

The reason why ItemX static constraints on F# tuples do not work is because System.Tuple<_,...,_> is only the encoded form of tuples, and not the static representation used by the compiler. 对F#元组的ItemX静态约束不起作用的原因是因为System.Tuple<_,...,_>只是元组的编码形式,而不是编译器使用的静态表示。 See 6.3.2 Tuple Expressions in the specification. 请参阅规范中的6.3.2元组表达式

However, with a little work, you can obtain the runtime encoding of a given tuple like so: 但是,通过一些工作,您可以获得给定元组的运行时编码,如下所示:

open System
//like get2a but generic return type
let inline get2b (t:^a) = (^a : (member Item2 : 'b) t)

let x = (1,2)
let y = (1,2,3)

get2b (box x :?> Tuple<int,int>)
get2b (box y :?> Tuple<int,int,int>)

You can do it using reflection: 你可以使用反射来做到这一点:

let inline get (t:^a) = t.GetType().GetProperty("Item2").GetValue(t,null) :?> string

Also, I would suggest that tuples are not really a great data structure for passing data around, they may be useful inside a function for small operations, but in case there is a frequent change in the structure, tuple can be really painful to work with 另外,我建议元组实际上并不是一个很好的数据结构来传递数据,它们在小型操作的函数中可能很有用,但是如果结构经常发生变化,那么元组可能真的很痛苦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM