如果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() => "()";
会很不错。
微软的反应式框架也有一个实现——我相信那个。这是:github.com/dotnet/reactive/blob/main/Rx.NET/Source/src/…
我选择unit
的原因是你可以使用using static Unit;
,然后在任何地方使用unit
,就好像它是内置类型一样。也因为它很简短。我不知道反应式框架也有类似的。以上是关于如果F#支持void类型,为啥我需要使用单位类型?的主要内容,如果未能解决你的问题,请参考以下文章