gpt4 book ai didi

c# - 函数式编程对覆盖的回答是什么?

转载 作者:太空狗 更新时间:2023-10-30 00:19:16 26 4
gpt4 key购买 nike

我对来自 OOP 和 C# 背景的函数式编程和 F# 都很熟悉,我注意到在函数式编程中,方法通常是静态的,并且在模块中根据类型(我能理解为什么)。

例如,要使用 list,您可以使用 List 模块中的函数,要使用 option,可以使用 选项模块等

但是,当我接受基类的参数并且派生类有更合适的实现时会发生什么?

在 OOP 中,将调用适当的实现,即派生实现,即使该对象是基类的静态对象,因为该成员已被覆盖

在函数式编程中会怎样?

如果你有基类型作为参数(你应该这样做),你只能使用它的函数,就像你只能在 OOP 中调用基的成员一样。
唯一的区别是在 OOP 中调用的成员是适当的成员。

最佳答案

您描述的覆盖场景,有一个基类绑定(bind)到子类型 Polymorphism .在您的情况下,您可以有一个通用接口(interface),例如 IEnumerable。这种多态性在 OOP 中很常见,但在 FP 中却不常见,后者更多地依赖于其他两种类型的多态性:Ad-Hoc 和 Parametric。

这方面的一个例子是类型类,在 Haskell 中你可以让一个函数接受类型 T 的任何参数,只要类型 T 是类型类 C 的一个实例,但是你的函数可以用通用的方式实现>您仍然可以通过添加仅适用于该特定实例 T 的函数来“覆盖”该通用定义,当使用该特定类型调用此类函数时,一般实现将被覆盖,请注意这将在编译时已知而不是编译-时间。

一个简单的例子是 Functors 和 Monads,fmap 函数可以根据函数 bindreturn 以通用方式为任何 Monad 实现,但您可以将 fmap 的特定实现添加到 list 和/或 option 中,比通用实现更高效。

我不是 100% 确定,但我认为在 C# 中你可以在 Linq 中进行这种优化,因为你可以为 SelectMany 定义更多重载,这相当于 bind.

不幸的是,在 F# 中没有这样的内置机制,尽管有一些方法对此进行编码(请参阅 FsControl 中的默认方法),但 F# 不仅仅是功能性的,它是多范式并且存在于 .NET 世界中(一个面向对象的世界)所以你已经准备好了 SubTyping 的覆盖。

话虽如此,值得一提的是,这更多是一种技术观点,但在大多数情况下,在设计方面与 OOP 中的覆盖并不一对一,因为这比 SubTyping 更通用。我的意思是,如果您将 OOP 设计迁移到 FP 并将类层次结构更改为假设联合体,您的泛型方法很可能最终会出现在 match 的 catch-all-other-cases 中(带有下划线的 | _ -> ) 和特定情况下的覆盖。

更新

这是您在评论中的问题的答案:

type MyType = 
static member Nth (x:seq<_>) = fun n -> printfn "General case"; Seq.nth n x
static member Nth (x:_ []) = fun n -> printfn "Override for []"; x.[n]

let bigSeq = seq {1..10000000}
let bigLst = [ 1..10000000 ]
let bigArr = [|1..10000000|]

MyType.Nth bigSeq 9000000
// General case
// Real: 00:00:00.217, CPU: 00:00:00.218, GC gen0: 0, gen1: 0, gen2: 0

MyType.Nth bigArr 9000000
// Override for []
// Real: 00:00:00.001, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0

MyType.Nth bigLst 9000000
// General case
// Real: 00:00:00.080, CPU: 00:00:00.078, GC gen0: 0, gen1: 0, gen2: 0

但是没有 [] 的覆盖:

MyType.Nth bigArr 9000000
// General case
// Real: 00:00:00.052, CPU: 00:00:00.046, GC gen0: 0, gen1: 0, gen2: 0

这就是重写在临时多态性(重载)中的工作方式。

通过使用 .NET 重载方法,您可以重写,但您可能会争辩说您不能走得太远,因为重载在调用站点得到解决,因此您不能在该调用之上定义另一个通用函数。

现在让我们假设我有一个类型类 Collection,它表示可以向上转换为 seq 的所有类型,还有一个函数 nth 如果我在 F# 中有类型类,我将能够编写如下内容:

// General implementation relaying in IEnumerable<_>
let nth n (x:Collection<_>) = Seq.nth n

// Specific implementation for arrays
let nth n (x:_ []) = x.[n]

不幸的是,这不会编译,因为 F# 中的重载仅适用于方法,不适用于函数,而且目前 F# 中没有类型类,但正如我提到的,有一些解决方法,使用 FsControl我可以写this这将实际编译并允许我运行相同的测试。

无论如何,如果遇到相同的情况,您将如何在 OOP 中编写代码,因为您无法访问 Seq 和 Array 的源代码?使用子类型多态性,您将无法在这种情况下覆盖任何内容。

关于c# - 函数式编程对覆盖的回答是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22789941/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com