如果支持void类型,为什么我需要在F#中使用单位类型?

时间:2013-12-20 13:37:17

标签: f# functional-programming void lambda unit-type

我读过这篇MSDN文章:

Unit Type (F#)

  

...单位类型是指示缺少特定类型的类型   值;单位类型只有一个值,作为一个   占位符,当没有其他值存在或需要时......   单元类型类似于C#和C ++等语言中的void类型。

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

  1. 为什么需要?
  2. 什么时候需要?
  3. 我不明白为什么不在F#中使用void类型,比如C#和C ++使用。

    如果我查看下表:

    Primitive Types (F#)

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

    我看到F#确实有一个void类型。所以我不明白为什么需要单位类型;看起来它与void非常相似。

    我认为它与功能语言范式有关,这就是为什么需要它,所以请...向我解释一下这个问题。

4 个答案:

答案 0 :(得分:13)

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

答案 1 :(得分:8)

请参阅维基百科的Unit Type

  

无效类型为单位类型

     

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

     

调用约定的区别

     

真实单位类型与虚空之间的第一个显着差异   type是单元类型可能始终是a的参数类型   函数,但void类型不能是C中参数的类型,   尽管它可能看起来是列表中的唯一参数。

     

存储差异

     

第二个值得注意的区别是空洞类型是空的   永远不会存储在记录类型中,即在结构或类中   C / C ++。相反,单位类型可以存储在记录中   函数式编程语言,即它可以表现为a的类型   领域;上面用C ++实现的单元类型也可以   存储。虽然这似乎是一个无用的功能,但它确实允许一个   实例,优雅地将集合实现为单元类型的映射;在   如果没有单位类型,人们仍然可以通过这种方式实现集合   为每个密钥存储一些其他类型的虚拟值。

答案 2 :(得分:4)

另一种看待它的方法是将()视觉化为一个arity为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演算的函数式语言中,函数接受单个参数并返回单个值。 currying支持多个参数。参数和返回值也可以是元组以支持多个值。

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

答案 3 :(得分:1)

本文解释了 void 的一些限制以及为什么您甚至可能希望在 C# 中使用 Unithttps://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() => "()";
}