Params в F# (функции с переменным числом параметров)
Работая в F#, я ни разу не сталкивался с необходимостью использовать нечто в этом роде, но тем не менее оно есть. У F# нет ключевого слова для создания таких функций, но мы можем использовать для этого атрибуты:
//using params analogue in F# type SomeBoilerplateType = static member Add ([<ParamArray>] x) = x |> (Array.map float) |> Array.sum SomeBoilerplateType.Add(1, 2) SomeBoilerplateType.Add(1,2,3,4,5) SomeBoilerplateType.Add([|for i in 0..10 -> i|])
Как вы думаете, какого типа будет такой метод? :)
Конечно,
int array -> int
.
Печально, что использовать это можно только в методах классов (как и, например, ad hoc-полиморфизм (секция "Overloaded Methods"), именованные и опциональные аргументы (перейдя по последней ссылке, промотайте вниз :) )).
Кстати, есть ещё кое-какие тонкости.
Пример с Item:
Например, мы можем объявить вот такую функцию:
Подробнее о type functions вы можете почитать в спецификации F#.
P.S.: Были кое-какие проблемы с отображением кода F#, я решил их. При использовании F# brush для SyntaxHighlighter'а нужно закомментить строки про symbolic-класс, иначе будут глюки.
Кстати, есть ещё кое-какие тонкости.
Индексаторы
Индексаторы являются "официальной" фишкой F#, только называются они не Indexers, как в C#, а Indexed Properties. На MSDN написано про них практически всё, кроме одной детали: вместо того, чтобы именовать свойство, используемое для индексирования, как Item, можно дать ему любое другое имя, но при этом также задать классу атрибут [<DefaultMember("name")>], где Name — имя свойства.Пример с Item:
//indexers for F# type Slowpoke() = let hidden = [|for i in 0..10 -> i|] let mutable current = 0 member this.Item with get(_) = let res = hidden.[current] current <- (current + 1) % hidden.Length System.Threading.Thread.Sleep(1000) res let slowpoke = new Slowpoke() slowpoke.[666] slowpoke.[666]Пример с атрибутом (заодно — другой вариант синтаксиса для свойства без сеттера):
open System.Reflection [<DefaultMember("AnotherName")>] type Slowpoke'() = let hidden = [|for i in 0..10 -> i|] let mutable current = 0 member this.AnotherName(_) = let res = hidden.[current] current <- (current + 1) % hidden.Length System.Threading.Thread.Sleep(1000) res let slowpoke' = new Slowpoke'() slowpoke'.[156]Кстати, на самом деле, для примера с Item компилятор просто сам добавляет этот атрибут:
typeof<Slowpoke>.GetCustomAttributes(false) > [|System.Reflection.DefaultMemberAttribute {MemberName = "Item"; TypeId = System.Reflection.DefaultMemberAttribute;}; ... |]
Функции с аргументами-типами (Type Functions)
Кстати, оtypeof
. Это функция. Не не простая, а так называемая Type Function — функция, которая принимает в качестве своих аргументов типы, а не какие-то значения. Такие функции можно объявлять только в модулях, в классах же, типах и выражениях их объявлять нельзя.Например, мы можем объявить вот такую функцию:
let set = new System.Collections.Generic.HashSet() let hasBeenAlreadyCalledWithThisType<'T> = not <| set.Add(typeof<'T>.Name) hasBeenAlreadyCalledWithThisType<int> //false hasBeenAlreadyCalledWithThisType<float> //false hasBeenAlreadyCalledWithThisType<int> //trueЭта функция будет вести список всех типов, с которыми она была вызвана и отвечать true/false в зависимости от того, "знаком" ли ей уже текущий тип.
Подробнее о type functions вы можете почитать в спецификации F#.
[<AutoOpen>]
Я просто процитирую спецификацию:When applied to an assembly and given a string argument, causes the namespace or module to be opened automatically when the assembly is referenced. When applied to a module without a string argument, causes the module to be opened automatically when the enclosing namespace or module is opened.
Компилятор, голос!
Можно заставить компилятор выдавать заданные нами сообщения с помощью атрибута[<CompilerMessage("SomeUserSpecifiedMessage", MessageNumber)>].
P.S.: Были кое-какие проблемы с отображением кода F#, я решил их. При использовании F# brush для SyntaxHighlighter'а нужно закомментить строки про symbolic-класс, иначе будут глюки.
на самом деле индексаторы это не "официальная" F#, просмотри ещё раз получше MSDN
ОтветитьУдалитьПосмотрел. Про "неофициальность" их нигде не увидел.
ОтветитьУдалитьСмотрим спецификацию:
"A property member is an indexer property if patidx is not the unit pattern (). Indexer properties called Item are special in the sense that they are accessible via the .[] notation. An Item property that takes one argument is accessed by using x.[i]; with two arguments by x.[i,j], and so on. Setter properties must return type unit."
Итак, с чего вы взяли то, что вы взяли?))