Скрытые возможности F#

Это беззастенчивая попытка подобного вопроса C#.

Итак, какие ваши любимые функции F# скрыты (или нет)?

Большинство функций, которые я использовал до сих пор, не совсем скрыты, но были довольно освежающими. Например, как просто перегрузить операторы по сравнению, например, с C# или VB.NET.

А также Async<T> помог мне сбрить какой-то настоящий уродливый код.

Я все еще плохо знаком с языком, поэтому было бы здорово узнать, какие другие функции используются в дикой природе.

11 ответов

Пользовательские числовые литералы могут быть определены путем предоставления модуля, имя которого начинается с NumericLiteral и который определяет определенные методы (FromZero, FromOne, так далее.).

В частности, вы можете использовать это, чтобы обеспечить гораздо более читаемый синтаксис для вызова LanguagePrimitives.GenericZero а также LanguagePrimitives.GenericOne:

module NumericLiteralG = begin
  let inline FromZero() = LanguagePrimitives.GenericZero
  let inline FromOne() = LanguagePrimitives.GenericOne
end

let inline genericFactorial n =
  let rec fact n = if (n = 0G) then 1G else n * (fact (n - 1G))
  fact n

let flt = genericFactorial 30.
let bigI = genericFactorial 30I

F# имеет малоиспользуемую функцию под названием "файлы подписи". У вас может быть большой файл реализации, полный открытых типов / методов / модулей / функций, но затем вы можете скрыть и выборочно представить эту функциональность для продолжения программы через файл сигнатуры. Таким образом, файл подписи действует как своего рода экран / фильтр, который позволяет вам делать сущности "общедоступными для этого файла", но "частными для остальной части программы".

Я чувствую, что это довольно убойная функция на платформе.Net, потому что единственный другой / предыдущий инструмент, который у вас есть для этого вида инкапсуляции, - это сборки. Если у вас есть небольшой компонент с несколькими связанными типами, который хочет видеть внутренние детали друг друга, но не хочет, чтобы эти типы были доступны всем этим битам, что вы можете сделать? Ну, вы можете сделать две вещи:

  1. Вы можете поместить этот компонент в отдельную сборку и сделать элементы, которые разделяются этими типами, "внутренними", а узкую часть, которую вы хотите, чтобы все остальные видели, "общедоступной", или
  2. Вы просто помечаете внутреннее содержимое как "внутреннее", но оставляете эти типы в своей гигантской сборке и просто надеетесь, что весь другой код в сборке решит не вызывать те элементы, которые были помечены только как "внутренние", потому что еще один тип необходим для его просмотра.,

По моему опыту, в больших программных проектах каждый всегда делает № 2, потому что #1 не является стартером по разным причинам (люди не хотят 50 небольших сборок, они хотят 1, 2 или 3 больших сборки, для других, возможно, - веские причины, не связанные с вопросом инкапсуляции, который я поднимаю (кроме того: все упоминают ILMerge, но никто не использует его)).

Итак, вы выбрали вариант № 2. Затем, год спустя, вы, наконец, решили реорганизовать этот компонент и обнаружили, что за последний год 17 других мест теперь вызывают этот "внутренний" метод, который действительно предназначен только для вызова этого другого типа, что делает его действительно Трудно выделить этот бит, потому что теперь все зависят от этих деталей реализации. Облом.

Дело в том, что в.Net нет хорошего способа создать внутрисобственную область / границу инкапсуляции небольшого размера. Часто "внутренний" слишком велик, а "частный" слишком мал.

... до F#. С помощью файлов сигнатур F# вы можете создать область инкапсуляции "этого файла исходного кода", пометив кучу вещей как общедоступных в файле реализации, чтобы весь остальной код в файле мог видеть его и отмечать его, но затем использовать файл подписи, скрывающий все детали, ожидает узкий общедоступный интерфейс, который компонент предоставляет остальному миру. Это счастливое. Определите три тесно связанных типа в одном файле, пусть они видят детали реализации друг друга, но только предоставляют действительно общедоступные материалы всем остальным. Выиграть!

Файлы подписи, возможно, не являются идеальной функцией для границ инкапсуляции внутри сборки, но они являются единственной такой функцией, которую я знаю, и поэтому я цепляюсь за них, как спасательный плот в океане.

TL; DR

Сложность - враг. Границы инкапсуляции являются оружием против этого врага. "private" - отличное оружие, но иногда слишком маленькое, чтобы его можно было применить, а "internal" часто слишком слаб, потому что так много кода (всей сборки и всех InternalsVisibleTo) может видеть внутренние вещи. F# предлагает область, большую, чем "private для типа", но меньшую, чем "вся сборка", и это очень полезно.

Интересно, что произойдет, если вы добавите

<appSettings>
  <add key="fsharp-navigationbar-enabled" value="true" />
</appSettings>

в ваш файл devenv.exe.config? (Используйте на свой риск.)

Переходя --warnon:1182 компилятору включаются предупреждения о неиспользуемых переменных; имена переменных, начинающиеся с подчеркивания, являются иммунными.

Автоматически сгенерированные функции сравнения для алгебраических типов данных (основанные на лексикографическом упорядочении) - хорошая функция, которая относительно неизвестна; увидеть

http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!548.entry

для примера.

Смотрите этот вопрос

F# оператор "?"

для получения информации об операторе вопросительного знака и о том, как он обеспечивает базовый языковой механизм для создания функции, похожей на "динамическую" в C#.

Да, F# не имеет никаких "скрытых" функций, но он, несомненно, обладает большой силой, упакованной в простой язык. Менее известная особенность языка - это то, где вы можете в основном включить утку, несмотря на тот факт, что F# является статически типизированным.

Не совсем скрытый, но как человек без ML это ускользнуло от меня на некоторое время:

Сопоставление с образцом может разлагаться сколь угодно глубоко на структуры данных.

Вот [невероятно произвольный] пример вложенного кортежа; это работает со списками или объединениями или любыми комбинациями вложенных значений:

let listEven =
  "Manipulating strings can be intriguing using F#".Split ' '
  |> List.ofArray
  |> List.map (fun x -> (x.Length % 2 = 0, x.Contains "i"), x)
  |> List.choose 
     ( function (true, true), s -> Some s 
              | _, "F#"         -> Some "language" 
              | _               -> None ) 

Использование F# в качестве служебного скриптового языка может быть недооценено. Энтузиасты F# имеют тенденцию быть квантами. Иногда вы хотите, чтобы что-то сделало резервные копии ваших MP3 (или десятков серверов баз данных), которые были бы немного более надежными, чем пакетные. Я охотился за современной заменой jscript / vbscript. В последнее время я использовал IronPython, но F# может быть более полным, а взаимодействие.NET менее громоздким.

Мне нравятся карри функции для развлекательной ценности. Покажите карри функцию в чисто процедурной / ООП программе как минимум для трех WTF. Начать с того, что это плохой способ получить F# конвертирование, хотя:)

Встроенные операторы в универсальных типах могут иметь различные универсальные ограничения:

type 'a Wrapper = Wrapper of 'a with
  static member inline (+)(Wrapper(a),Wrapper(b)) = Wrapper(a + b)
  static member inline Exp(Wrapper(a)) = Wrapper(exp a)

let objWrapper = Wrapper(obj())
let intWrapper = (Wrapper 1) + (Wrapper 2)
let fltWrapper = exp (Wrapper 1.0)

(* won''t compile *)
let _ = exp (Wrapper 1)

Там нет никаких скрытых функций, потому что F# находится в режиме разработки. Все, что у нас есть, это технический предварительный просмотр, который меняется каждые два месяца.

см. http://research.microsoft.com/fsharp/

Другие вопросы по тегам