Здравствуйте, Пельмешко, Вы писали:
П>Размышлял на досуге, зачём введён тип unit в F#...
П>Причём это не просто синоним void, а обычный класс Microsoft.FSharp.Core.Unit, да ещё и с int _dummy внутри
П>Хотя unit никогда не создаётся, всегда возвращается адресный null...
Я этот вопрос себе тоже задавал, пришел к следующим выводам:
Нужен был просто именно значение некоторого типа, которое никому не интересно. Т.е. само значение есть, но что именно там — не важно. И это как раз отличает его от void-а, который есть "ничто", т.е. даже значения его нет.
П>Должен же быть смысл, какую-нибудь проблему это решает ![](/Forum/Images/smile.gif)
Конечно решает!
Имея такой тип, можно комбинировать в штатном порядке функции, принимающие и возвращающие 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.
>