Typy
Wartość typu to wartość, która klasyfikuje inne wartości. Wartość sklasyfikowana przez typ jest określana jako zgodna z tym typem. System typów M składa się z następujących rodzajów typów:
Typy pierwotne, które klasyfikują wartości pierwotne (
binary
,date
,datetime
datetimezone
duration
list
logical
null
number
record
text
time
type
), a także zawierają wiele typów abstrakcyjnych (function
,table
,any
anynonnull
i )none
Typy rekordów, które klasyfikują wartości rekordów na podstawie nazw pól i typów wartości
Typy list, które klasyfikują listy przy użyciu typu podstawowego pojedynczego elementu
Typy funkcji, które klasyfikują wartości funkcji na podstawie typów ich parametrów i zwracanych wartości
Typy tabel, które klasyfikują wartości tabeli na podstawie nazw kolumn, typów kolumn i kluczy
Typy dopuszczane wartości null, które klasyfikuje wartość null oprócz wszystkich wartości sklasyfikowanych przez typ podstawowy
Typy typów, które klasyfikują wartości, które są typami
Zestaw typów pierwotnych none
Wszystkie wartości funkcji są zgodne z typem function
abstrakcyjnym , wszystkie wartości tabeli do typu table
abstrakcyjnego , wszystkie wartości typu abstrakcyjnego , wszystkie wartości any
inne niż null do typu anynonnull
abstrakcyjnego , a nie wartości typu abstrakcyjnego none
. Wyrażenie typu none
musi zgłosić błąd lub zakończyć się niepowodzeniem, ponieważ nie można wygenerować żadnej wartości zgodnej z typem none
. Należy pamiętać, że typy function
pierwotne i table
są abstrakcyjne, ponieważ żadna funkcja lub tabela nie jest bezpośrednio z tych typów, odpowiednio. Typy record
pierwotne i list
nie są abstrakcyjne, ponieważ reprezentują otwarty rekord bez zdefiniowanych pól i listę typów odpowiednio.
Wszystkie typy, które nie są elementami członkowskimi zamkniętego zestawu typów pierwotnych oraz ich odpowiedniki dopuszczające wartość null, są zbiorczo określane jako typy niestandardowe. Typy niestandardowe można zapisywać przy użyciu elementu type-expression
:
wyrażenie-typ:
wyrażenie-podstawowe
type
typ podstawowy
type:
wyrażenie-podstawowe
typ podstawowy
typ podstawowy:
typ pierwotny
typ rekordu
typ listy
typ funkcji
typ tabeli
typ dopuszczalny do wartości null
typ-pierwotny: jeden z
any anynonnull binary date datetime datetimezone duration function list logical
none null number record table text time type
Nazwy typów pierwotnych to kontekstowe słowa kluczowe rozpoznawane tylko w kontekście typu . Użycie nawiasów w kontekście typu przenosi gramatykę z powrotem do kontekstu wyrażenia regularnego, co wymaga użycia słowa kluczowego typu, aby wrócić do kontekstu typu. Aby na przykład wywołać funkcję w kontekście typu , można użyć nawiasów:
type nullable ( Type.ForList({type number}) )
// type nullable {number}
Nawiasy mogą również służyć do uzyskiwania dostępu do zmiennej, której nazwa zderza się z nazwą typu pierwotnego:
let record = type [ A = any ] in type {(record)}
// type {[ A = any ]}
W poniższym przykładzie zdefiniowano typ klasyfikujący listę liczb:
type { number }
Podobnie w poniższym przykładzie zdefiniowano typ niestandardowy, który klasyfikuje rekordy z obowiązkowymi polami o nazwie X
i Y
których wartości są liczbami:
type [ X = number, Y = number ]
Przypisany typ wartości jest uzyskiwany przy użyciu standardowej funkcji biblioteki Value.Type, jak pokazano w następujących przykładach:
Value.Type( 2 ) // type number
Value.Type( {2} ) // type list
Value.Type( [ X = 1, Y = 2 ] ) // type record
Operator is
służy do określania, czy typ wartości jest zgodny z danym typem, jak pokazano w następujących przykładach:
1 is number // true
1 is text // false
{2} is list // true
Operator as
sprawdza, czy wartość jest zgodna z danym typem, i zgłasza błąd, jeśli nie jest. W przeciwnym razie zwraca oryginalną wartość.
Value.Type( 1 as number ) // type number
{2} as text // error, type mismatch
Należy pamiętać, że is
operatory i as
akceptują tylko typy pierwotne dopuszczające wartość null jako prawy operand. Język M nie zapewnia środków sprawdzania wartości pod kątem zgodności z typami niestandardowymi.
Typ X
jest zgodny z typem Y
, jeśli i tylko wtedy, gdy wszystkie wartości zgodne X
również z Y
. Wszystkie typy są zgodne z typem any
i nie none
są zgodne z typem none
. Na poniższym wykresie przedstawiono relację zgodności. (Zgodność typu jest refleksyjna i przechodnia. Tworzy kratę z typem any
u góry i typem none
jako wartość dolną). Nazwy typów abstrakcyjnych są ustawiane kursywą.
Następujące operatory są definiowane dla wartości typów:
Operator | Result |
---|---|
x = y |
Equal |
x <> y |
Not equal |
x ?? y |
Coalesce |
Natywnym typem wartości typu jest typ type
wewnętrzny .
Typy pierwotne
Typy w języku M tworzą rozłączną hierarchię zakorzenione w typie any
, czyli typ, który klasyfikuje wszystkie wartości. Każda wartość języka M jest zgodna z dokładnie jednym podtypem pierwotnym .any
Zamknięty zestaw typów pierwotnych pochodnych z typu any
jest następujący:
-
type null
, który klasyfikuje wartość null. -
type logical
, który klasyfikuje wartości true i false. -
type number
, który klasyfikuje wartości liczbowe. -
type time
, który klasyfikuje wartości czasu. -
type date
, który klasyfikuje wartości dat. -
type datetime
, który klasyfikuje wartości daty/godziny. -
type datetimezone
, który klasyfikuje wartości daty/godziny/strefy czasowej. -
type duration
, który klasyfikuje wartości czasu trwania. -
type text
, który klasyfikuje wartości tekstowe. -
type binary
, który klasyfikuje wartości binarne. -
type type
, który klasyfikuje wartości typów. -
type list
, który klasyfikuje wartości listy. -
type record
, który klasyfikuje wartości rekordów. -
type table
, który klasyfikuje wartości tabeli. -
type function
, który klasyfikuje wartości funkcji. -
type anynonnull
, który klasyfikuje wszystkie wartości z wyłączeniem wartości null. -
type none
, który klasyfikuje brak wartości.
Dowolny typ
Typ any
jest abstrakcyjny, klasyfikuje wszystkie wartości w języku M, a wszystkie typy w języku M są zgodne z elementem any
. Zmienne typu any
mogą być powiązane ze wszystkimi możliwymi wartościami. Ponieważ any
jest abstrakcyjna, nie można przypisać jej do wartości — to znaczy, że żadna wartość nie jest bezpośrednio typu any
.
Typy list
Każda wartość, która jest listą, jest zgodna z typem list
wewnętrznym , który nie nakłada żadnych ograniczeń na elementy w wartości listy.
typ listy:
{
typ elementu}
typ elementu:
typ
Wynikiem oceny typu listy jest wartość typu listy, którego typ podstawowy to list
.
W poniższych przykładach przedstawiono składnię deklarowania homogenicznych typów list:
type { number } // list of numbers type
{ record } // list of records type
{{ text }} // list of lists of text values
Wartość jest zgodna z typem listy, jeśli wartość jest listą, a każdy element w tej wartości listy jest zgodny z typem elementu typu listy.
Typ elementu typu listy wskazuje granicę: wszystkie elementy zgodnej listy są zgodne z typem elementu.
Typy rekordów
Każda wartość, która jest rekordem, jest zgodna z rekordem typu wewnętrznego, który nie nakłada żadnych ograniczeń dotyczących nazw pól ani wartości w ramach wartości rekordu. Wartość typu rekordu służy do ograniczania zestawu prawidłowych nazw, a także typów wartości, które mogą być skojarzone z tymi nazwami.
typ rekordu:
[
open-record-marker]
[
opcja field-specification-list]
[
field-specification-list , open-record-marker]
lista-specyfikacji pól:
specyfikacja pola
field-specification,
field-specification-list
specyfikacja pola:
optional
opt-name field-type-specificationopt
specyfikacja typu pola:
=
typ-pola
typ-pola:
type
open-record-marker:
...
Wynikiem oceny typu rekordu record
W poniższych przykładach przedstawiono składnię deklarowania typów rekordów:
type [ X = number, Y = number]
type [ Name = text, Age = number ]
type [ Title = text, optional Description = text ]
type [ Name = text, ... ]
Typy rekordów są domyślnie zamykane , co oznacza, że dodatkowe pola, które nie znajdują się na liście pólpoznania , nie mogą być obecne w zgodnych wartościach. Uwzględnienie znacznika openrecord-w typie rekordu deklaruje, że typ ma być otwarty, co zezwala na pola, które nie znajdują się na liście specyfikacji pola. Następujące dwa wyrażenia są równoważne:
type record // primitive type classifying all records
type [ ... ] // custom type classifying all records
Wartość jest zgodna z typem rekordu, jeśli wartość jest rekordem, a każda specyfikacja pola w typie rekordu jest satysfakcjonująca. Specyfikacja pola jest spełniona, jeśli którakolwiek z następujących wartości jest prawdziwa:
Nazwa pola pasująca do identyfikatora specyfikacji istnieje w rekordzie, a skojarzona wartość jest zgodna z typem specyfikacji
Specyfikacja jest oznaczona jako opcjonalna i nie można odnaleźć odpowiedniej nazwy pola w rekordzie
Zgodna wartość może zawierać nazwy pól, które nie są wymienione na liście specyfikacji pól, jeśli typ rekordu jest otwarty i tylko wtedy, gdy typ rekordu jest otwarty.
Typy funkcji
Każda wartość funkcji jest zgodna z typem function
pierwotnym , który nie nakłada żadnych ograniczeń dotyczących typów parametrów formalnych funkcji lub zwracanej wartości funkcji. Niestandardowa wartość typu funkcji służy do umieszczania ograniczeń typu dla podpisów zgodnych wartości funkcji.
typ funkcji:
function (
parametr-specification-listopt)
function-return-type
parametr-specification-list:
required-parameter-specification-list
required-parameter-specification-list,
optional-parameter-specification-list
opcjonalna lista-specyfikacji parametrów
required-parameter-specification-list:
required-parameter-specification
required-parameter-specification,
required-parameter-specification-list
required-parameter-specification:
specyfikacja parametrów
optional-parameter-specification-list:
opcjonalna specyfikacja parametrów
optional-parameter-specification,
optional-parameter-specification-list
opcjonalna specyfikacja parametrów:
optional
specyfikacja parametrów
specyfikacja parametrów:
parametr-nazwa parametru typ-parametru
funkcja-return-type:
assertion
twierdzenie:
as
typ-pierwotny dopuszczany do wartości null
Wynikiem oceny typu funkcji jest wartość typu, którego typ podstawowy to function
.
W poniższych przykładach przedstawiono składnię deklarowania typów funkcji:
type function (x as text) as number
type function (y as number, optional z as text) as any
Wartość funkcji jest zgodna z typem funkcji, jeśli zwracany typ wartości funkcji jest zgodny z zwracanym typem typu funkcji, a każda specyfikacja parametru typu funkcji jest zgodna z pozycjonalnie odpowiadającym mu parametrem formalnym funkcji. Specyfikacja parametru jest zgodna z parametrem formalnym, jeśli określony typ parametru jest zgodny z typem parametru formalnego, a specyfikacja parametru jest opcjonalna, jeśli parametr formalny jest opcjonalny.
Nazwy parametrów formalnych są ignorowane na potrzeby określania zgodności typu funkcji.
Określenie parametru jako opcjonalnego powoduje, że jego typ jest dopuszczający wartość null. Następujące typy funkcji tworzą identyczne typy funkcji:
type function (optional x as text) as any
type function (optional x as nullable text) as any
Typy tabel
Wartość typu tabeli służy do definiowania struktury wartości tabeli.
typ tabeli:
table
typ wiersza
typ wiersza:
[
opcja field-specification-list]
Wynikiem oceny typu tabeli jest wartość typu, którego typ podstawowy to table
.
Typ wiersza tabeli określa nazwy kolumn i typy kolumn tabeli jako typ zamkniętego rekordu. Aby wszystkie wartości tabeli były zgodne z typem , jego typ table
wiersza jest typem record
(pustym typem otwartego rekordu). W związku z tym tabela typów jest abstrakcyjna, ponieważ żadna wartość tabeli nie może mieć typu wiersza typu table
(ale wszystkie wartości tabeli mają typ wiersza zgodny z typem table
wiersza typu). W poniższym przykładzie przedstawiono konstrukcję typu tabeli:
type table [A = text, B = number, C = binary]
// a table type with three columns named A, B, and C
// of column types text, number, and binary, respectively
Wartość typu tabeli zawiera również definicję kluczy wartości tabeli. Klucz to zestaw nazw kolumn. Co najwyżej jeden klucz można wyznaczyć jako klucz podstawowy tabeli. (W języku M klucze tabeli nie mają znaczenia semantycznego. Jednak w przypadku zewnętrznych źródeł danych, takich jak bazy danych lub źródła danych OData, typowe jest definiowanie kluczy w tabelach. Dodatek Power Query używa kluczowych informacji w celu zwiększenia wydajności zaawansowanych funkcji, takich jak operacje sprzężenia krzyżowego).
Standardowe funkcje Type.TableKeys
biblioteki , Type.AddTableKey
i Type.ReplaceTableKeys
mogą służyć do uzyskiwania kluczy typu tabeli, dodawania klucza do typu tabeli i zastępowania wszystkich kluczy typu tabeli.
Type.AddTableKey(tableType, {"A", "B"}, false)
// add a non-primary key that combines values from columns A and B
Type.ReplaceTableKeys(tableType, {})
// returns type value with all keys removed
Typy dopuszczające wartości null
W przypadku dowolnego type T
wariantu dopuszczalnego wartości null można uzyskać przy użyciu typu dopuszczalnego wartości null:
typ dopuszczalny do wartości null:
nullable
typ
Wynik jest typem abstrakcyjnym, który zezwala na wartości typu T lub wartości null
.
42 is nullable number // true null is
nullable number // true
Ascription T type nullable
zmniejsza się do deskrypcji type null
lub type
T. (Pamiętaj, że typy dopuszczające wartość null są abstrakcyjne i żadna wartość nie może być bezpośrednio typu abstrakcyjnego).
Value.Type(42 as nullable number) // type number
Value.Type(null as nullable number) // type null
Standardowe funkcje Type.IsNullable
biblioteki i Type.NonNullable
mogą służyć do testowania typu pod kątem wartości null i usuwania wartości null z typu.
Następująca blokada (dla dowolnego elementu type T
):
-
type T
jest zgodny ztype nullable T
-
Type.NonNullable(type T)
jest zgodny ztype T
Poniżej przedstawiono odpowiedniki parowania (dla dowolnego type T
elementu ):
type nullable any
any
Type.NonNullable(type any)
type anynonnull
type nullable none
type null
Type.NonNullable(type null)
type none
type nullable nullable T
type nullable T
Type.NonNullable(Type.NonNullable(type T))
Type.NonNullable(type T)
Type.NonNullable(type nullable T)
Type.NonNullable(type T)
type nullable (Type.NonNullable(type T))
type nullable T
Przypisany typ wartości
Przypisany typ wartości to typ, do którego zadeklarowano zgodność wartości.
Wartość może być przypisana do typu przy użyciu funkcji Value.ReplaceType
biblioteki . Ta funkcja zwraca nową wartość z przypisanym typem lub zgłasza błąd, jeśli nowy typ jest niezgodny z wartością.
Gdy wartość jest przypisana do typu, występuje tylko ograniczone sprawdzanie zgodności:
- Typ, który jest przypisany, musi być nie abstrakcyjny, niepusty i zgodny z wewnętrznym (natywnym) typem pierwotnym wartości.
- Gdy typ niestandardowy definiujący strukturę jest przypisywany, musi być zgodny ze strukturą wartości.
- W przypadku rekordów: typ musi być zamknięty, musi zdefiniować tę samą liczbę pól co wartość i nie może zawierać żadnych pól opcjonalnych. (Nazwy pól i typy pól typu zastąpią te, które są obecnie skojarzone z rekordem. Jednak istniejące wartości pól nie będą sprawdzane względem nowych typów pól.
- W przypadku tabel: typ musi definiować tę samą liczbę kolumn co wartość. (Nazwy kolumn i typy kolumn typu zastąpią te, które są obecnie skojarzone z tabelą. Jednak istniejące wartości kolumn nie będą sprawdzane względem nowych typów kolumn).
- W przypadku funkcji: typ musi definiować tę samą liczbę wymaganych parametrów, a także taką samą liczbę parametrów opcjonalnych, jak wartość. (Parametr typu i asercji zwracanych, a także jego nazwy parametrów, zastąpi te skojarzone z bieżącym typem wartości funkcji. Jednak nowe asercji nie będą miały wpływu na rzeczywiste zachowanie funkcji).
- W przypadku list: wartość musi być listą. (Jednak istniejące elementy listy nie będą sprawdzane względem nowego typu elementu).
Funkcje biblioteki mogą zdecydować się na obliczenia i przypisanie typów złożonych do wyników na podstawie przypisanych typów wartości wejściowych.
Przypisany typ wartości można uzyskać przy użyciu funkcji Value.Type
biblioteki . Na przykład:
Value.Type( Value.ReplaceType( {1}, type {number} )
// type {number}
Równoważność typów i zgodność
Równoważność typów nie jest zdefiniowana w języku M. Implementacja języka M może opcjonalnie użyć własnych reguł do przeprowadzania porównań równości między wartościami typów. Porównywanie dwóch wartości typu równości powinno być obliczane, true
jeśli są one uważane za identyczne przez implementację i false
w przeciwnym razie. W obu przypadkach zwracana odpowiedź musi być spójna, jeśli te same dwie wartości są wielokrotnie porównywane. Należy pamiętać, że w ramach danej implementacji porównanie niektórych identycznych wartości typu (takich jak (type text) = (type text)
) może zwracać true
wartość , porównując inne (takie jak (type [a = text]) = (type [a = text])
) może nie.
Zgodność między danym typem a typem pierwotnym dopuszczanym do wartości null można określić przy użyciu funkcji Type.Is
biblioteki , która akceptuje dowolną wartość typu jako pierwszą i nullable wartość typu pierwotnego jako drugi argument:
Type.Is(type text, type nullable text) // true
Type.Is(type nullable text, type text) // false
Type.Is(type number, type text) // false
Type.Is(type [a=any], type record) // true
Type.Is(type [a=any], type list) // false
W języku M nie ma obsługi określania zgodności danego typu z typem niestandardowym.
Biblioteka standardowa zawiera kolekcję funkcji w celu wyodrębnienia definiowania cech z typu niestandardowego, więc określone testy zgodności można zaimplementować jako wyrażenia języka M. Poniżej przedstawiono kilka przykładów. Aby uzyskać szczegółowe informacje, zapoznaj się ze specyfikacją biblioteki M.
Type.ListItem( type {number} )
// type number
Type.NonNullable( type nullable text )
// type text
Type.RecordFields( type [A=text, B=time] )
// [ A = [Type = type text, Optional = false],
// B = [Type = type time, Optional = false] ]
Type.TableRow( type table [X=number, Y=date] )
// type [X = number, Y = date]
Type.FunctionParameters(
type function (x as number, optional y as text) as number)
// [ x = type number, y = type nullable text ]
Type.FunctionRequiredParameters(
type function (x as number, optional y as text) as number)
// 1
Type.FunctionReturn(
type function (x as number, optional y as text) as number)
// type number