【问题标题】:Construct list terminated with a different type构造列表以不同的类型终止
【发布时间】:2020-12-08 22:14:48
【问题描述】:

我是否需要一个定制的 sum 类型才能定义一个 A 类型列表的数据类型,其中最后一个元素是 B 类型(因此必须重新实现其上定义的所有不错的函数)。

type ListTerminatedWith<'a,'b> = 
    | Cons of 'a * ListTerminatedWith<'a,'b> 
    | Nil of 'b

好的,那么显而易见的是:

type ListTerminatedWith<'a,'b> = List<'a> * 'b

但是,实际上我只想在到达那里时将终止值附加到列表中(真正的问题是关于 Seq,而不是 List)。

一个奇怪的例子是让我们把值的总和说成一个字符串。

所以(在完整的伪代码中......我不希望它编译)

let x: ListTerminatedWith<int,string> = [ 1;2;3;"6"]

这个值是由一个函数创建的,其中“6”被附加,当函数想要终止时,就像创建一个序列一样。

【问题讨论】:

  • 也许您可以使用Either&lt;'a, 'b&gt; 类型的列表来解决?但无论哪种方式,您可能都必须编写 sum 等函数,因为默认值不起作用。
  • 这允许 'a 和 'b 的任意组合......我不想重新发明的是 map/bind/fold 等......但也许我被它困住了
  • 好吧,你有一个非常具体的案例,恐怕你必须这样做,除非这两种类型都展示了可以与 SRTP 一起使用的方法。在这种情况下,您可以使用更简单的标准函数重新定义。在你自己的集合类型上定义映射、绑定、过滤、折叠是很常见的,尤其是如果它们不能是IEnumerable
  • 它是具体的,但事实上,正如我所展示的,它实际上是 List 的概括,其中 Nil 也有一个值。 (对我而言)很有趣的是,List 的这种微不足道的扩展实际上似乎无法表达,而不涉及原子类型。
  • Fwiw,你没有一个简单的 List 扩展,你有自己的类型。列表定义为List&lt;'t&gt;,您的类型定义为MyList&lt;'a, 'b&gt;。任何现有代码如何能够处理任意类型参数,在您的情况下,还附加了特定规则?

标签: functional-programming f#


【解决方案1】:

我可能会将您的类型定义为空,或者是由列表和终止值组成的对:

type TerminatedList<'a, 'b> = 
  | Empty
  | NonEmpty of list<'a> * 'b

这使得无效状态无法表示,但它也为表示的某些部分重用标准列表。您仍然需要为您的新类型重新定义自己的标准函数,例如 map,但至少您可以经常重用 List 的内置函数。例如,要定义map,您可以重用List.map,并进行一些额外的包装:

module TerminatedList = 
  let map f = function 
    | Empty -> Empty 
    | NonEmpty(a, b) -> NonEmpty(List.map f a, f b)

我不确定是否有合理的方法来概括这种管道(因为您通常需要对额外的终止元素做一些特殊的事情),所以它可能很乏味,但添加任何您需要的功能应该很容易.

【讨论】:

  • 我以 list 为例,因为它很简单,真正的问题是关于终止符的惰性(或至少延迟)评估,即 seq 后跟一个 'b,你熟悉 Ultimate Monad,我认为它在 F# 编译器中使用吗?...它实际上是 ListTerminatedWith,其中标准 List 是 ListTerminatedWith
  • tbh,我可能已经回答了我自己的问题...如果 f# 编译器必须滚动它自己的版本(有效的 Seq 以 'a 终止)那么它(显然)不可能.
  • @MrDatKookerellaLtd 与任何一元类型一样,您应该定义其bindreturnmap,可能还有其他一些用于CE,我怀疑这将永远是“自动的”,但是看看 F#+ 以了解一些接近 HKT 的情况。这里以编译器的Eventually&lt;'T&gt;为例:github.com/dotnet/fsharp/blob/…
  • TerminatedList.map 中,你怎么能有一个在'a'b 上运行的函数(f)?
  • @Abel 是的,我接受这一点,但是必须在 sum 类型上从第一原则构建这些东西比 Tomas 的例子要多,我们真的不希望软件工程成为一种练习构建“原始”的东西
猜你喜欢
  • 2017-02-04
  • 1970-01-01
  • 2016-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-19
  • 2022-11-05
相关资源
最近更新 更多