如何使用接口映射记录

2024-03-16

给定以下类型和值

type Item<'a, 'b> = Item of 'a * 'b

type X<'a, 'b> = {
    y: Item<'a, int>
    z: Item<'b, bool>
}

let a = {
    y = Item (false, 2); 
    z = Item (1, true) 
}

我想创建一个通用映射函数

tmap: X<'a, 'b> -> X<'x, 'y>

使用接口和对象表达式。到目前为止我的方法是

type ITransform<'a, 'b, 'x, 'y> = abstract Apply : Item<'a,'b> -> Item<'x,'y>

let inline tmap (f:ITransform<_,_,_,_>) ({y = yi; z = zi}) =
    {
        y = f.Apply yi
        z = f.Apply zi
    }

但是我收到错误z = f.Apply zi as f被推断为ITransform<'a, int, 'b, int>

let mkStringify () =
    { 
        new ITransform<_,_,_,_> with 
            member __.Apply(Item(a,b)) = Item (sprintf "%A" a, b)
    }

let mkDublicate () =
    { 
        new ITransform<_,_,_,_> with 
            member __.Apply(Item(a,b)) = Item ((a, a), b)
    }

let x = tmap (mkStringify()) a
let y = tmap (mkDoublicate()) a

这是一个后续问题如何使用 F# 在记录结构上定义 fmap https://stackoverflow.com/questions/41123405/how-to-define-a-fmap-on-a-record-structure-with-f/41124608#41124608.
我可以通过使用答案之一中描述的静态成员函数方法来解决这个问题,但不能使用接口方法


Your ITransform定义并不比函数好。您可以直接使用签名函数Item<'a,'b> -> Item<'x,'y>,效果是一样的。

使用接口的原因是你可以有不同的通用参数每次调用该方法时。但这反过来意味着通用参数不能固定在接口本身上。他们必须在方法上:

type ITransform = abstract Apply<'a, 'b, 'x, 'y> : Item<'a,'b> -> Item<'x,'y>

或者您可以完全删除它们,编译器会将它们从签名中删除:

type ITransform = abstract Apply : Item<'a,'b> -> Item<'x,'y>

Now tmap编译良好:即使接口本身不是通用的,它的方法Apply是,因此每次调用都可以有不同的通用参数。

然而,现在你有另一个问题:实现这样的接口mkStringify并不是那么简单。现在Apply是完全通用的,它的实现不能返回特定类型,例如string。鱼与熊掌不可兼得:界面是对消费者的“承诺”,也是对实施者的“需求”,所以如果你的消费者期望能够做到“anything“,那么实施者必须遵守并实施”一切".

要解决这个问题,请退一步思考您的问题:您到底想要实现什么?你想把什么转化成什么?到目前为止,在我看来,你正试图强迫所有论点中的第一个论点Items to string,同时保持第二个参数不变。如果这是目标,那么定义ITransform很明显:

type ITransform = abstract Apply : Item<'a,'b> -> Item<string,'b>

这反映了这个想法:传入的第一个参数Item可能是任何东西,它会被转换为string,第二个参数可以是任何东西,并且它保持不变。

有了这个定义,两者tmap and mkStringify将编译。

如果这不是您的目标,请描述一下,我们也许可以找到其他解决方案。但请记住上面与蛋糕相关的评论:如果你想要tmap为任何类型工作,那么实现者ITransform还必须支持任何类型。

Update

从评论中的讨论可以明显看出,真正的问题描述如下:转换函数应该转换Item到其他东西,并保持第二个参数不变。并且“其他东西”对于两者来说都是相同的Items.

这样,实现就变得清晰了:接口本身应该修复输出的“其他”部分,并且该方法应该采用任何类型作为输入:

type ITransform<'target> = abstract Apply : Item<'a, 'b> -> Item<'target, 'b>

根据这个定义,所有三个函数tmap, mkStringify, and mkDuplicate将编译。我们找到了一个共同点:对接口消费者有足够的承诺,对接口实现者没有太多要求。

话说回来,我认为你实际上并不需要这里的界面,这太过分了。不能使用函数的原因是函数在按值传递时将失去其通用性,因此不适用于不同类型的参数。然而,可以通过两次传递该函数来解决这个问题。在这两种情况下它都会失去通用性,但它会以不同的方式失去通用性——即每次都会用不同的参数实例化。是的,两次传递同一个函数感觉很尴尬,但它的语法仍然比接口少:

let inline tmap f1 f2 ({y = yi; z = zi}) =
    {
        y = f1 yi
        z = f2 zi
    }

let stringify x =
    let f (Item(a,b)) = Item (sprintf "%A" a, b)
    tmap f f x

stringify a
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用接口映射记录 的相关文章

  • 从父类返回子类

    我有一个构建器类 它从大多数方法返回自身以允许菊花链 为了使此功能适用于子类 我希望父方法返回子类的实例 以便子方法可以链接到末尾 public class BaseBuilder
  • 通用控制器/服务类中注释 @ModelAtribute 和 @PreAutorize 的属性

    我正在尝试为我的项目设置一个通用类 到目前为止我得到这个代码 https github com klebermo blog cms blob master src main java com config generic controlle
  • 从非泛型类重写抽象泛型方法

    基类 class Drawer public abstract void Draw
  • 何时使用接口,何时使用高阶函数?

    给定一个具有以下层的 ASP NET MVC 应用程序 UI 视图 CSS Javascript 等 控制器 服务 包含业务逻辑和数据访问 没有单独的数据访问层的原因是我正在使用 SQL 类型提供程序 以下代码可能不起作用 因为它只是原始草
  • .NET 中可以使用通用 BitConverter.GetBytes 吗?

    是否可以创建类似的方法BitConverter GetBytes 也接受作为输入范围类型的Object 不使用编组处理here https stackoverflow com questions 1455581 generic bitcon
  • 运行时的泛型[重复]

    这个问题在这里已经有答案了 有两个程序 为什么第一个代码有效 我希望它在访问元素时抛出运行时异常 因为添加了字符串而不是整数 相似地 第二个代码在访问元素时抛出运行时异常 尽管它能够轻松地在 arrayList 中添加 Integer 尽管
  • 如何使用泛型而不是注释来实现构建器类?

    我想写一个通用的建造者阶级它包装任何 java 类并提供特定样式的 setter 函数 我不确定这是否可以称为 动态生成的函数 当我有一个豆子般的 Pojo 课时 即 class Pojo public void setValue int
  • 为什么不自动装箱泛型的 Java 基本类型?

    Java 不允许在通用数据结构中使用原始类型 例如 不允许使用 ArrayList 原因是 原始类型不能直接转换为Object 然而 Java 1 5 确实支持自动装箱 并且包装类在通用数据结构中工作 那么为什么编译器不能将其自动装箱到 A
  • 该组件没有由 uri 标识的资源

    我想创建一个通用数据网格以在我的所有视图 用户控件上使用 这是我的结构 Class Library called Core Class called ViewBase public class ViewBase UserControl pu
  • Swift Generics 在使用继承时不会实例化泛型

    我有课Alpha and Berry class Alpha class Berry Alpha 我有一个使用继承及其泛型的函数 func myFunc
  • 泛型和系统集合

    迁移到 NET 2 0 后 是否还有理由继续使用 systems Collections 命名空间 除了维护遗留代码之外 是否应该始终使用泛型命名空间 在大多数情况下 泛型集合的执行速度比非泛型集合更快 并且为您带来强类型集合的好处 比较
  • F# 之于 IronPython/IronRuby 就像 C# 之于 VB.NET 一样?

    我刚刚听了Chris Smith 谈论 F 的播客 http www code magazine com codecast index aspx messageid 7feb501f 25c8 432a 9624 97082f1e75e8他
  • Java泛型中类型参数的前向引用

    根据 Java 泛型常见问题解答http www angelikalanger com GenericsFAQ FAQSections TypeParameters html FAQ302 http www angelikalanger c
  • 向下投射通用元素类型

    public class ConfigControlBase
  • 如何使用 Unity 动态注册通用类?

    我有一个包含很多类 300 和 BaseClass 的程序集 我想用接口注册一个泛型类 统一后 您必须在 Name如果你想解析接口的对象数组 我想要一个对象数组主视图模型自动地 有没有办法通过反射来自动执行此操作 有什么建议么 示例 伪 p
  • Java 泛型从类创建数组

    我有一个层次结构 其中正方形 三角形和圆形都从形状延伸 我有一个工作方法 public void someMethod File file new File File with squares ThirdPartyClass foo new
  • F# 查询,按单列对多个值进行分组

    我有一个 F sql 查询 需要对每组中的两列求和 let financials query for data in dbData do groupValBy data earning data losses data store into
  • 数组与列表的性能

    假设您需要一个需要频繁迭代的整数列表 数组 我的意思是非常频繁 原因可能有所不同 但可以说它位于大容量处理的最内层循环的核心 一般来说 人们会选择使用列表 List 因为它们的大小具有灵活性 最重要的是 msdn 文档声称列表在内部使用数组
  • 我可以避免使用泛型来避免急于解决特征实现的歧义吗?

    考虑以下 Rust 代码 use std collections HashMap use std hash Hash trait Foo
  • C# 抽象泛型方法

    C net 3 5 我正在尝试创建一个具有通用方法的基类 从它继承的类应该指定方法的类型 这样做的前提是创建管理过滤的类 所以我有 public abstract class FilterBase NEED Help Declaring t

随机推荐