Скрытые особенности F #

Это непродуманная попытка аналогичного вопроса С#.

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

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

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

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

Ответ 1

Пользовательские числовые литералы могут быть определены путем предоставления модуля, имя которого начинается с 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

Ответ 2

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

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

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

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

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

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

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

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

TL; DR

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

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

для примера.

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

Не совсем скрытый, но как человек, не связанный с 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 ) 

Ответ 9

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

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

Ответ 10

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

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)

Ответ 11

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

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