[F#] Unit type
От: Пельмешко Россия blog
Дата: 21.07.09 18:03
Оценка:
Размышлял на досуге, зачём введён тип unit в F#...
Причём это не просто синоним void, а обычный класс Microsoft.FSharp.Core.Unit, да ещё и с int _dummy внутри
Хотя unit никогда не создаётся, всегда возвращается адресный null...

Должен же быть смысл, какую-нибудь проблему это решает

Я понимаю, что в ФП функции обязаны возвращать что-либо, но зачем вводить отдельный тип, если можно
| 1 -> ()
за сценой превращать в:
case 1: return;


Как то читал Эрика Липперта про вариантность void, подумал по началу, что unit — просто уловка, вариантный аналог void'а. Проверил — это не так...

Пока писал этот пост пришло в голову, что может unit нужен для поддержки функциональных типов, всяким FastFunc<T1,T2> нельзя же указать System.Void в качестве generic-параметра...

Я правильно понимаю предназначение unit?

22.07.09 00:56: Перенесено из '.NET'
Re: [F#] Unit type
От: samius Япония http://sams-tricks.blogspot.com
Дата: 21.07.09 18:39
Оценка: 12 (1)
Здравствуйте, Пельмешко, Вы писали:

П>Размышлял на досуге, зачём введён тип unit в F#...

П>Причём это не просто синоним void, а обычный класс Microsoft.FSharp.Core.Unit, да ещё и с int _dummy внутри
П>Хотя unit никогда не создаётся, всегда возвращается адресный null...

Я этот вопрос себе тоже задавал, пришел к следующим выводам:
Нужен был просто именно значение некоторого типа, которое никому не интересно. Т.е. само значение есть, но что именно там — не важно. И это как раз отличает его от void-а, который есть "ничто", т.е. даже значения его нет.

П>Должен же быть смысл, какую-нибудь проблему это решает

Конечно решает!
Имея такой тип, можно комбинировать в штатном порядке функции, принимающие и возвращающие unit. С void-ом такое не прокатит.

П>Я понимаю, что в ФП функции обязаны возвращать что-либо, но зачем вводить отдельный тип, если можно

П>
| 1 -> ()
за сценой превращать в:

П>
case 1: return;

нет, void нас не устраивает, т.к. функция должна возвращать хоть что-нибудь.

П>Как то читал Эрика Липперта про вариантность void, подумал по началу, что unit — просто уловка, вариантный аналог void'а. Проверил — это не так...


именно к вариантности не имеет отношения, как мне кажется.

П>Пока писал этот пост пришло в голову, что может unit нужен для поддержки функциональных типов, всяким FastFunc<T1,T2> нельзя же указать System.Void в качестве generic-параметра...

А вот это — оно самое. Здесь нам не надо подразделять на Func<T,...> и Action<T,...>. Всегда обходимся одним способом.

П>Я правильно понимаю предназначение unit?

Вобщем — да. Это заменитель void, но более гибкий.

Правда есть один трюк, который я не до конца понимаю.
> ignore;;
val it : ('a -> unit) = <fun:clo@0>


при том, что сигнатура метода ignore в рефлекторе определена как
public static void ignore<T>(T value)


Т.е. void интерпретируется как и unit.

Но не совсем:
> let f1 () = ()
- let f2 () = ()
- let f3 = f1 >> f2;;

val f1 : unit -> unit
val f2 : unit -> unit
val f3 : (unit -> unit)

объявленные так функции мы можем комбинировать.

и так тоже:
> let f4 = f1 >> ignore;;  

val f4 : (unit -> unit)


а так уже нельзя:
> let f5 = ignore >> f1;; 

  let f5 = ignore >> f1;;
  ----^^

stdin(15,5): error FS0030: Value restriction. The value 'f5' has been inferred to have generic type
        val f5 : ('_a -> unit)
Either make the arguments to 'f5' explicit or, if you do not intend for it to be generic, add a type annotation.
>
Re: [F#] Unit type
От: _FRED_ Черногория
Дата: 21.07.09 18:53
Оценка: 16 (2)
Здравствуйте, Пельмешко, Вы писали:

П>Должен же быть смысл, какую-нибудь проблему это решает


void нельзя использовать как параметр дженерик-типа. Самодельный unit решает эту задачу. Такой тип есть в Common Generics Library:

The Unit type is a filler type. This is useful, for example, when an existing generic type is used, but one of its type arguments is not required for the particular application.


  // The single-valued type.
  [Serializable]
  public enum Unit { Unit };


Я использую такой:

  [Serializable]
  public struct Unit : IEquatable<Unit>
  {
    #region Fields

    private const int HashCodeMagicNumber = 67981;

    #endregion Fields

    #region Properties

    public static Unit Value {
      [DebuggerStepThrough]
      get { return default(Unit); }
    }

    #endregion Properties

    #region Overrides

    public override bool Equals(object obj) {
      return obj is Unit;
    }

    public override int GetHashCode() {
      return HashCodeMagicNumber;
    }

    #endregion Overrides

    #region IEquatable<Unit> Members

    public bool Equals(Unit other) {
      return true;
    }

    #endregion IEquatable<Unit> Members

    #region Operators

    [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "left", Justification = "We are can not change the operator signature.")]
    [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "right", Justification = "We are can not change the operator signature.")]
    public static bool operator ==(Unit left, Unit right) {
      return true;
    }

    [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "left", Justification = "We are can not change the operator signature.")]
    [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "right", Justification = "We are can not change the operator signature.")]
    public static bool operator !=(Unit left, Unit right) {
      return false;
    }

    #endregion Operators
  }
Help will always be given at Hogwarts to those who ask for it.
Re[2]: [F#] Unit type
От: desco США http://v2matveev.blogspot.com
Дата: 21.07.09 22:33
Оценка: 10 (1)
Здравствуйте, samius, Вы писали:


S>Т.е. void интерпретируется как и unit.


S>Но не совсем:

S>
>> let f1 () = ()
S>- let f2 () = ()
S>- let f3 = f1 >> f2;;

S>val f1 : unit -> unit
S>val f2 : unit -> unit
S>val f3 : (unit -> unit)
S>

S>объявленные так функции мы можем комбинировать.

S>и так тоже:

S>
>> let f4 = f1 >> ignore;;  

S>val f4 : (unit -> unit)
S>


S>а так уже нельзя:

S>
>> let f5 = ignore >> f1;; 

S>  let f5 = ignore >> f1;;
S>  ----^^

S>stdin(15,5): error FS0030: Value restriction. The value 'f5' has been inferred to have generic type
S>        val f5 : ('_a -> unit)
S>Either make the arguments to 'f5' explicit or, if you do not intend for it to be generic, add a type annotation.
>>
S>


Value restriction не имеет отношения к unit. Automatic generalization применяется к функциям и простым типам данных. Функции, определенные как значения автоматически не обобщаются.

> let a x = 5;;

val a : 'a -> int

> let b x = x + 1;;

val b : int -> int

> let c = a >> b;;

  let c = a >> b;;
  ----^

stdin(22,5): error FS0030: Value restriction. The value 'c' has been inferred to have generic type
    val c : ('_a -> int)
Either make the arguments to 'c' explicit or, if you do not intend for it to be generic, add a type annotation.


простой фикс — явно задать аргументы
> let c x = (a >> b) x;;

val c : 'a -> int
Re[3]: [F#] Unit type
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.07.09 04:07
Оценка:
Здравствуйте, desco, Вы писали:

D>Здравствуйте, samius, Вы писали:


S>>а так уже нельзя:

S>>
>>> let f5 = ignore >> f1;; 

S>>  let f5 = ignore >> f1;;
S>>  ----^^

S>>stdin(15,5): error FS0030: Value restriction. The value 'f5' has been inferred to have generic type
S>>        val f5 : ('_a -> unit)
S>>Either make the arguments to 'f5' explicit or, if you do not intend for it to be generic, add a type annotation.
>>>
S>>


D>Value restriction не имеет отношения к unit. Automatic generalization применяется к функциям и простым типам данных. Функции, определенные как значения автоматически не обобщаются.


Что-то я тут лопухнул. Спасибо.
Re: [F#] Unit type
От: FR  
Дата: 22.07.09 12:39
Оценка:
Здравствуйте, Пельмешко, Вы писали:

П>Размышлял на досуге, зачём введён тип unit в F#...


А он там и не введен, а взят из прородителя OCaml'a

П>Причём это не просто синоним void, а обычный класс Microsoft.FSharp.Core.Unit, да ещё и с int _dummy внутри

П>Хотя unit никогда не создаётся, всегда возвращается адресный null...

а void как раз введен, его в OСaml нет.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.