【问题标题】:F# member constraints on tuples元组上的 F# 成员约束
【发布时间】:2011-07-28 09:41:12
【问题描述】:

当我意识到我在某个地方需要一个额外的价值时,我通常会有一个“哦,是的”时刻写 F#。这通常很容易通过向传递的元组添加另一个值来完成。但是,这意味着各种地图/排序/收集/等。需要更新,特别是 fst/snd 函数仅适用于长度为 2 的元组。

这不是一个大问题,但在探索性开发过程中已经很烦人了,我想我会写一个帮助程序来减轻烦恼:

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

但是,这两个版本都不起作用。第一个,get2,不会编译,“预期 1 表达式,得到 2”。第二个 get2a 将编译,但随后不能用于元组:“类型 '(int * string)' 不支持任何名为 'get_Item2' 的运算符”。

有什么方法可以做到不涉及大量重载吗? 带有嘈杂的OverloadID 注释 (F# 2.0 中不需要注释)

【问题讨论】:

  • 除此之外 - 为什么 C++ 仍然是唯一具有灵活、实用泛型的语言 - 约束会被推断出来,会起作用,并且由于数字模板参数在任何情况下都是不必要的......跨度>
  • 自 F# 2.0 起不再需要 OverloadID 属性
  • 嘿,很高兴知道!

标签: generics f# constraints


【解决方案1】:

ItemX 对 F# 元组的静态约束不起作用的原因是因为System.Tuple<_,...,_> 只是元组的编码形式,而不是编译器使用的静态表示。请参阅规范中的6.3.2 Tuple Expressions

但是,通过一些工作,您可以获得给定元组的运行时编码,如下所示:

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>)

【讨论】:

    【解决方案2】:

    您可以使用反射来做到这一点:

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

    另外,我认为元组并不是一个很好的传递数据的数据结构,它们可能在函数内部用于小型操作,但如果结构经常发生变化,元组可能真的很痛苦一起工作

    【讨论】:

    • 我曾尝试过 Eamon 不久前想做的事情,如果我没记错的话 - 你的解决方案是唯一的。
    • 使用反射获取元组的任意第n个元素:stackoverflow.com/questions/5252628/…
    • 嗯,看起来反射会破坏类型推断;我猜它是长长的重载列表。
    • @Eamon Nerbonne - 不幸的是,重载也会破坏类型推断:fssnip.net/6V
    • 例如在 C++ 中是可能的,Haskell 的类型类也可以使类似的事情成为可能。即使是简单的重载work,类型推断也是可能的,只是没有执行。真的,静态推理是微不足道的,所以我看不出静态检查语言与它有什么关系——显然它只是没有实现。
    猜你喜欢
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    • 2017-12-18
    • 2020-12-20
    • 1970-01-01
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多