如果F#支持void类型,为啥我需要使用单位类型?

Posted

技术标签:

【中文标题】如果F#支持void类型,为啥我需要使用单位类型?【英文标题】:Why do I need to use the unit type in F# if it supports the void type?如果F#支持void类型,为什么我需要使用单位类型? 【发布时间】:2014-01-09 09:19:54 【问题描述】:

我阅读了这篇 MSDN 文章:

Unit Type (F#)

...单位类型是一种类型,表示没有特定的 价值;单位类型只有一个值,它充当 不存在或不需要其他值时的占位符... 单元类型类似于 C# 和 C++ 等语言中的 void 类型...

所以...好吧,我明白了,单元类型就是这样一种类型,它只有一个值()。但我有一些问题:

    为什么需要它? 什么时候需要?

我不明白为什么不在 F# 中使用 void 类型,就像 C# 和 C++ 使用一样。

如果我看下表:

Primitive Types (F#)

Type   .NET Type    Description  
void   Void         Indicates no type or value.

我看到 F# 确实有一个 void 类型。所以我不明白为什么需要单位类型;看起来和void很像。

我想它与函数式语言范式有关,这就是为什么需要它,所以请...向我解释一下。

【问题讨论】:

见:What does this '()' notation mean? 我已经阅读了您对其他问题的回答,这很好:) 但我有一个新问题。如果我使用下一个代码:let b () = System.DateTime.Now;;System.Console.WriteLine(b);;,为什么它会在控制台输出中返回Program+clo@16,它是什么? 见this和this 因为 b 绑定到一个函数。你可以用 b() 调用它 应该是System.Console.Writeline(b());; 【参考方案1】:

在 C# 中,没有 void 类型的值可以用作参数类型。此外,void 不能用作泛型类型参数(例如,C# 需要使用并行的 Func<...>Action<...> 委托类型,但 F# 只需要一个函数类型 ... -> ...,它可以对两者进行抽象)。在许多情况下,这最终极大地简化了 F# 编程;例如,执行一些副作用但不返回值的 Async 操作是 Async<unit> 类型的实例,但在 C# 中无法创建相应的 Task<void> 或其他任何东西。

【讨论】:

【参考方案2】:

参见***中的Unit Type

虚空类型作为单位类型

在 C、C++、C# 和 Java 中,void 表示空类型。单位类型 在 C 中是 struct ,但 C 禁止空结构 语言规范。相反,void 的使用方式是 模拟单元类型的一些(但不是全部)属性,如 详情如下。

调用约定的不同

真正的单位类型和虚空之间的第一个显着区别 type 是单位类型可能始终是参数的类型 函数,但 void 类型不能是 C 中参数的类型, 尽管它可能作为列表中的唯一参数出现。

存储的区别

第二个显着的区别是 void 类型,为空,可以 从不存储在记录类型中,即在结构或类中 C/C++。相反,单元类型可以存储在记录中 函数式编程语言,即它可以显示为 场地;上面C++中单元类型的实现也可以 存储。虽然这似乎是一项无用的功能,但它确实允许 优雅地将集合实现为单元类型的映射的实例;在 在没有单元类型的情况下,仍然可以通过这种方式实现集合 为每个键存储一些另一种类型的虚拟值。

【讨论】:

【参考方案3】:

另一种看待它的方法是将 () 可视化为元组,元组为 0。

鉴于 () 用于分隔元组,我们得到

(abc, def, xyx) a tuple with arity of 3
(abc, def) a tuple with arity of 2
(abc) a tuple with arity of 1, which can be reduced to abc
() a tuple with arity of 0, called unit

在基于 lambda 演算的函数式语言中,函数采用单个参数并返回单个值。柯里化支持多个参数。参数和返回值也可以是元组来支持多个值。

我对unit/()的解释,是没有值,表示为一个元组。

【讨论】:

【参考方案4】:

本文解释了void 的一些限制,以及为什么您甚至可能希望在 C# 中使用 Unit:https://chtenb.dev/?page=unit-cs

最重要的是,您不能将void 用作泛型类型中的类型参数,例如Task<void>。使用单位类型而不是 void 可以解决这个问题。

这是本文中使用的 Unit 实现。

public struct Unit : IEquatable<Unit>

  public static readonly Unit unit;
  public override bool Equals(object obj) => obj is Unit;
  public override int GetHashCode() => 0;
  public static bool operator ==(Unit left, Unit right) => left.Equals(right);
  public static bool operator !=(Unit left, Unit right) => !(left == right);
  public bool Equals(Unit other) => true;
  public override string ToString() => "()";

【讨论】:

请不要发布仅链接的答案。您应该将所有重要的细节都放在答案本身中,并且只链接来支持您的内容。 @Enigmativity 已修复 我知道这篇文章定义了Unit.unit,因为它不能做Unit.Unit,但我建议Unit.Default 改为坚持正常的C# 命名约定。另外,添加public override string ToString() =&gt; "()"; 会很不错。 微软的反应式框架也有一个实现——我相信那个。这是:github.com/dotnet/reactive/blob/main/Rx.NET/Source/src/… 我选择unit 的原因是你可以使用using static Unit;,然后在任何地方使用unit,就好像它是内置类型一样。也因为它很简短。我不知道反应式框架也有类似的。

以上是关于如果F#支持void类型,为啥我需要使用单位类型?的主要内容,如果未能解决你的问题,请参考以下文章

当一个函数无返回值时,函数的类型应定义为啥

为啥我们需要 void 函数? [关闭]

为啥不能将不完整的类型强制转换为 void?

为啥我无法在具有 void 返回类型的异步函数中捕获异常?

为啥 F# 的类型推断如此善变?

为啥 nvcc 失败允许将 T * 类型的指针转​​换为 void *?