Spec-Zone.ru › Sanctuary Def

sanctuary-def

sanctuary-def — это система типов во время выполнения для JavaScript. Она облегчает определение склеенных функций JavaScript, чётко указывающих количество аргументов, к которым они могут быть применены, и типы этих аргументов.

Обычно пакет импортируется как $:

const $ = require ('sanctuary-def');

Следующим шагом является определение среды. Среда — это массив типов. env — это среда, содержащая все встроенные типы JavaScript. Она может использоваться в качестве основы для сред, которые включают пользовательские типы в дополнение к встроенным типам:

//    Integer :: Type
const Integer = '...';

//    NonZeroInteger :: Type
const NonZeroInteger = '...';

//    env :: Array Type
const env = $.env.concat ([Integer, NonZeroInteger]);

Конструкторы типов, такие как List :: Type -> Type, не могут быть включены в среду, так как они не имеют правильного типа. Однако можно использовать конструктор типов для определения фиксированного количества конкретных типов:

//    env :: Array Type
const env = $.env.concat ([
  List ($.Number),                // :: Type
  List ($.String),                // :: Type
  List (List ($.Number)),         // :: Type
  List (List ($.String)),         // :: Type
  List (List (List ($.Number))),  // :: Type
  List (List (List ($.String))),  // :: Type
]);

Это не только утомительно, но и невозможно перечислить все возможные типы, так как их бесконечно много. Вместо этого следует использовать Unknown:

//    env :: Array Type
const env = $.env.concat ([List ($.Unknown)]);

Следующим шагом является определение функции def для среды с помощью $.create:

//    def :: String -> StrMap (Array TypeClass) -> Array Type -> Function -> Function
const def = $.create ({checkTypes: true, env});

Опция checkTypes определяет, включена ли проверка типов. Это позволяет платить за производительность проверки типов во время выполнения только во время разработки. Например:

//    def :: String -> StrMap (Array TypeClass) -> Array Type -> Function -> Function
const def = $.create ({
  checkTypes: process.env.NODE_ENV === 'development',
  env,
});

def — это функция для определения функций. Например:

//    add :: Number -> Number -> Number
const add =
def ('add')                           // name
    ({})                              // type-class constraints
    ([$.Number, $.Number, $.Number])  // input and output types
    (x => y => x + y);                // implementation

[$.Number, $.Number, $.Number] указывает, что add принимает два аргумента типа Number, по одному за раз, и возвращает значение типа Number.

Применение add к двум аргументам по одному за раз даёт ожидаемый результат:

add (2) (2);
// => 4

Применение add к нескольким аргументам сразу приводит к выбросу исключения:

add (2, 2, 2);
// ! TypeError: ‘add’ applied to the wrong number of arguments
//
//   add :: Number -> Number -> Number
//          ^^^^^^
//            1
//
//   Expected one argument but received three arguments:
//
//     - 2
//     - 2
//     - 2

Применение add к одному аргументу создаёт функцию, ожидающую оставшийся аргумент. Это известно как частичное применение. Частичное применение позволяет определять более специфичные функции в терминах более общих:

//    inc :: Number -> Number
const inc = add (1);

inc (7);
// => 8

Неявное приведение типов в JavaScript часто скрывает источник ошибок типа. Рассмотрим следующую функцию:

//    _add :: Number -> Number -> Number
const _add = x => y => x + y;

Подпись типа указывает, что _add принимает аргументы типа Number, но это не проверяется. Это позволяет игнорировать ошибки типа:

_add ('2') ('2');
// => '22'

add, с другой стороны, выбрасывает исключение, если к нему применяются аргументы неправильных типов:

add ('2') ('2');
// ! TypeError: Invalid value
//
//   add :: Number -> Number -> Number
//          ^^^^^^
//            1
//
//   1)  "2" :: String
//
//   The value at position 1 is not a member of ‘Number’.

Проверка типов выполняется по мере предоставления аргументов (а не после предоставления всех аргументов), поэтому ошибки типов сообщаются рано:

add ('X');
// ! TypeError: Invalid value
//
//   add :: Number -> Number -> Number
//          ^^^^^^
//            1
//
//   1)  "X" :: String
//
//   The value at position 1 is not a member of ‘Number’.

Типы

Понятие типа — это множество значений. Можно представить значение типа Type как функцию типа Any -> Boolean, которая проверяет значения на принадлежность к множеству (хотя это упрощение).

Unknown :: Type

Тип, используемый для представления отсутствующей информации о типе. Например, тип [] — это Array ???.

Может использоваться с конструкторами типов при определении сред. Учитывая конструктор типов List :: Type -> Type, можно использовать List ($.Unknown) для включения бесконечного числа типов в среду:

  • List Number
  • List String
  • List (List Number)
  • List (List String)
  • List (List (List Number))
  • List (List (List String))
  • ...

Void :: Type

Тип без обитаемых значений.

Может использоваться для передачи информации о том, что параметр типа алгебраического типа данных не будет использован. Например, будущее типа Future Void String никогда не будет отклонено.

Any :: Type

Тип, включающий все значения JavaScript.

AnyFunction :: Type

Тип, включающий все значения функции Function.

Arguments :: Type

Тип, включающий все объекты arguments.

Array :: Type -⁠> Type

Конструктор однородных типов массивов Array.

Array0 :: Type

Тип, единственным членом которого является [].

Array1 :: Type -⁠> Type

Конструктор одноэлементных типов массивов Array.

Array2 :: Type -⁠> Type -⁠> Type

Конструктор гетерогенных типов массивов Array длиной 2. ['foo', true] является членом Array2 String Boolean.

Boolean :: Type

Тип, включающий true и false.

Buffer :: Type

Тип, включающий все объекты Buffer.

Date :: Type

Тип, включающий все значения Date.

ValidDate :: Type

Тип, включающий все значения Date за исключением new Date (NaN).

Descending :: Type -⁠> Type

Конструктор типа Descending.

Either :: Type -⁠> Type -⁠> Type

Конструктор типа Either.

Error :: Type

Тип, включающий все значения Error, включая значения более конкретных конструкторов, таких как SyntaxError и TypeError.

Fn :: Type -⁠> Type -⁠> Type

Двухместный конструктор типа для типов функций с одним аргументом. $.Fn (I) (O) представляет I -> O, тип функций, которые принимают значение типа I и возвращают значение типа O.

Function :: NonEmpty (Array Type) -⁠> Type

Конструктор типов Function.

Примеры:

  • $.Function ([$.Date, $.String]) представляет тип Date -> String; и
  • $.Function ([a, b, a]) представляет тип (a, b) -> a.

HtmlElement :: Type

Тип, включающий все HTML-элементы.

Identity :: Type -⁠> Type

Конструктор типа Identity.

JsMap :: Type -⁠> Type -⁠> Type

Конструктор для типов Map. Например, $.JsMap ($.Number) ($.String) — это тип, включающий все встроенные объекты Map, ключи которых — числа, а значения — строки.

JsSet :: Type -⁠> Type

Конструктор для типов Set. Например, $.JsSet ($.Number) — это тип, включающий все встроенные объекты Set, значения которых — числа.

Maybe :: Type -⁠> Type

Конструктор типа Maybe.

END_OF_DOCUMENT_MARKER

Module :: Type

Тип, включающий все модули ES.

NonEmpty :: Type -⁠> Type

Конструктор для непустых типов. Например, String является типом, включающим все значения типа String, кроме ''.

Указанный тип должен удовлетворять спецификациям Monoid и Setoid.

Null :: Type

Тип, единственный член которого — null.

Nullable :: Type -⁠> Type

Конструктор для типов, включающих null в качестве члена.

Number :: Type

Тип, включающий все примитивные значения Number (включая NaN).

PositiveNumber :: Type

Тип, включающий все значения Number больше нуля.

NegativeNumber :: Type

Тип, включающий все значения Number меньше нуля.

ValidNumber :: Type

Тип, включающий все значения Number, кроме NaN.

NonZeroValidNumber :: Type

Тип, включающий все значения ValidNumber, кроме 0 и -0.

FiniteNumber :: Type

Тип, включающий все значения ValidNumber, кроме Infinity и -Infinity.

NonZeroFiniteNumber :: Type

Тип, включающий все значения FiniteNumber, кроме 0 и -0.

PositiveFiniteNumber :: Type

Тип, включающий все значения FiniteNumber больше нуля.

NegativeFiniteNumber :: Type

Тип, включающий все значения FiniteNumber меньше нуля.

Integer :: Type

Тип, включающий все целые числа в диапазоне [Number.MIN_SAFE_INTEGER .. Number.MAX_SAFE_INTEGER].

NonZeroInteger :: Type

Тип, включающий все значения Integer, кроме 0 и -0.

NonNegativeInteger :: Type

Тип, включающий все неотрицательные значения Integer (включая -0). Также известен как множество натуральных чисел по ISO 80000-2:2009.

PositiveInteger :: Type

Тип, включающий все значения Integer больше нуля.

NegativeInteger :: Type

Тип, включающий все значения Integer меньше нуля.

Object :: Type

Тип, включающий все значения "обычных" объектов. В частности, значения, созданные с помощью:

  • синтаксиса литералов объектов;
  • Object.create; или
  • оператора new в сочетании с Object или пользовательской функцией-конструктором.

Pair :: Type -⁠> Type -⁠> Type

Конструктор типа Pair.

RegExp :: Type

Тип, включающий все значения RegExp.

GlobalRegExp :: Type

Тип, включающий все значения RegExp, у которых флаг global равен true.

См. также NonGlobalRegExp.

NonGlobalRegExp :: Type

Тип, включающий все значения RegExp, у которых флаг global равен false.

См. также GlobalRegExp.

StrMap :: Type -⁠> Type

Конструктор для однородных типов Object.

Например, {foo: 1, bar: 2, baz: 3} является членом StrMap Number, а {foo: 1, bar: 2, baz: 'XXX'} — нет.

String :: Type

Тип, включающий все примитивные значения String.

RegexFlags :: Type

Тип, включающий стандартные флаги RegExp:

  • ''
  • 'g'
  • 'i'
  • 'm'
  • 'gi'
  • 'gm'
  • 'im'
  • 'gim'

Symbol :: Type

Тип, включающий все значения Symbol.

Type :: Type

Тип, включающий все значения Type.

TypeClass :: Type

Тип, включающий все значения TypeClass.

Undefined :: Type

Тип, единственный член которого — undefined.

env :: Array Type

Массив типов:

  • AnyFunction
  • Arguments
  • Array (Unknown)
  • Array2 (Unknown) (Unknown)
  • Boolean
  • Buffer
  • Date
  • Descending (Unknown)
  • Either (Unknown) (Unknown)
  • Error
  • Fn (Unknown) (Unknown)
  • HtmlElement
  • Identity (Unknown)
  • JsMap (Unknown) (Unknown)
  • JsSet (Unknown)
  • Maybe (Unknown)
  • Module
  • Null
  • Number
  • Object
  • Pair (Unknown) (Unknown)
  • RegExp
  • StrMap (Unknown)
  • String
  • Symbol
  • Type
  • TypeClass
  • Undefined

test :: Array Type -⁠> Type -⁠> a -⁠> Boolean

Принимает окружение, тип и любое значение. Возвращает true если значение является членом типа; false в противном случае.

Окружение имеет значение только в том случае, если тип содержит переменные типа.

Конструкторы типов

sanctuary-def предоставляет несколько функций для определения типов.

NullaryType :: String -⁠> String -⁠> Array Type -⁠> (Any -⁠> Boolean) -⁠> Type

Конструктор типов для типов без переменных типа (например, Number).

Для определения нулевого типа t необходимо предоставить:

  • название t (экспонировано как t.name);

  • ссылку на документацию t (экспонировано как t.url);

  • массив супертипов (экспонировано как t.supertypes); и

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

Например:

//    Integer :: Type
const Integer = $.NullaryType
  ('Integer')
  ('http://example.com/my-package#Integer')
  ([])
  (x => typeof x === 'number' &&
        Math.floor (x) === x &&
        x >= Number.MIN_SAFE_INTEGER &&
        x <= Number.MAX_SAFE_INTEGER);

//    NonZeroInteger :: Type
const NonZeroInteger = $.NullaryType
  ('NonZeroInteger')
  ('http://example.com/my-package#NonZeroInteger')
  ([Integer])
  (x => x !== 0);

//    rem :: Integer -> NonZeroInteger -> Integer
const rem =
def ('rem')
    ({})
    ([Integer, NonZeroInteger, Integer])
    (x => y => x % y);

rem (42) (5);
// => 2

rem (0.5);
// ! TypeError: Invalid value
//
//   rem :: Integer -> NonZeroInteger -> Integer
//          ^^^^^^^
//             1
//
//   1)  0.5 :: Number
//
//   The value at position 1 is not a member of ‘Integer’.
//
//   See http://example.com/my-package#Integer for information about the Integer type.

rem (42) (0);
// ! TypeError: Invalid value
//
//   rem :: Integer -> NonZeroInteger -> Integer
//                     ^^^^^^^^^^^^^^
//                           1
//
//   1)  0 :: Number
//
//   The value at position 1 is not a member of ‘NonZeroInteger’.
//
//   See http://example.com/my-package#NonZeroInteger for information about the NonZeroInteger type.

UnaryType :: Foldable f => String -⁠> String -⁠> Array Type -⁠> (Any -⁠> Boolean) -⁠> (t a -⁠> f a) -⁠> Type -⁠> Type

Конструктор типов для типов с одной переменной типа (например, Array).

Для определения унарного типа t a необходимо предоставить:

  • название t (экспонировано как t.name);

  • ссылку на документацию t (экспонировано как t.url);

  • массив супертипов (экспонировано как t.supertypes);

  • предикат, принимающий любое значение, которое является членом каждого из указанных супертипов, и возвращающий true если (и только если) значение является членом t x для некоторого типа x;

  • функцию, которая принимает любое значение типа t a и возвращает значения типа a, содержащиеся в t; и

  • тип a.

Например:

const show = require ('sanctuary-show');
const type = require ('sanctuary-type-identifiers');

//    maybeTypeIdent :: String
const maybeTypeIdent = 'my-package/Maybe';

//    Maybe :: Type -> Type
const Maybe = $.UnaryType
  ('Maybe')
  ('http://example.com/my-package#Maybe')
  ([])
  (x => type (x) === maybeTypeIdent)
  (maybe => maybe.isJust ? [maybe.value] : []);

//    Nothing :: Maybe a
const Nothing = {
  'isJust': false,
  'isNothing': true,
  '@@type': maybeTypeIdent,
  '@@show': () => 'Nothing',
};

//    Just :: a -> Maybe a
const Just = x => ({
  'isJust': true,
  'isNothing': false,
  '@@type': maybeTypeIdent,
  '@@show': () => `Just (${show (x)})`,
  'value': x,
});

//    fromMaybe :: a -> Maybe a -> a
const fromMaybe =
def ('fromMaybe')
    ({})
    ([a, Maybe (a), a])
    (x => m => m.isJust ? m.value : x);

fromMaybe (0) (Just (42));
// => 42

fromMaybe (0) (Nothing);
// => 0

fromMaybe (0) (Just ('XXX'));
// ! TypeError: Type-variable constraint violation
//
//   fromMaybe :: a -> Maybe a -> a
//                ^          ^
//                1          2
//
//   1)  0 :: Number
//
//   2)  "XXX" :: String
//
//   Since there is no type of which all the above values are members, the type-variable constraint has been violated.

BinaryType :: Foldable f => String -⁠> String -⁠> Array Type -⁠> (Any -⁠> Boolean) -⁠> (t a b -⁠> f a) -⁠> (t a b -⁠> f b) -⁠> Type -⁠> Type -⁠> Type

Конструктор типов для типов с двумя переменными типа (например, Array2).

Для определения бинарного типа t a b необходимо предоставить:

  • название t (экспонировано как t.name);

  • ссылку на документацию t (экспонировано как t.url);

  • массив супертипов (экспонировано как t.supertypes);

  • предикат, принимающий любое значение, которое является членом каждого из указанных супертипов, и возвращающий true если (и только если) значение является членом t x y для некоторых типов x и y;

  • функцию, которая принимает любое значение типа t a b и возвращает значения типа a , содержащиеся в t;

  • функцию, которая принимает любое значение типа t a b и возвращает значения типа b , содержащиеся в t;

  • тип a; и

  • тип b.

Например:

const type = require ('sanctuary-type-identifiers');

//    pairTypeIdent :: String
const pairTypeIdent = 'my-package/Pair';

//    $Pair :: Type -> Type -> Type
const $Pair = $.BinaryType
  ('Pair')
  ('http://example.com/my-package#Pair')
  ([])
  (x => type (x) === pairTypeIdent)
  (({fst}) => [fst])
  (({snd}) => [snd]);

//    Pair :: a -> b -> Pair a b
const Pair =
def ('Pair')
    ({})
    ([a, b, $Pair (a) (b)])
    (fst => snd => ({
       'fst': fst,
       'snd': snd,
       '@@type': pairTypeIdent,
       '@@show': () => `Pair (${show (fst)}) (${show (snd)})`,
     }));

//    Rank :: Type
const Rank = $.NullaryType
  ('Rank')
  ('http://example.com/my-package#Rank')
  ([$.String])
  (x => /^(A|2|3|4|5|6|7|8|9|10|J|Q|K)$/.test (x));

//    Suit :: Type
const Suit = $.NullaryType
  ('Suit')
  ('http://example.com/my-package#Suit')
  ([$.String])
  (x => /^[\u2660\u2663\u2665\u2666]$/.test (x));

//    Card :: Type
const Card = $Pair (Rank) (Suit);

//    showCard :: Card -> String
const showCard =
def ('showCard')
    ({})
    ([Card, $.String])
    (card => card.fst + card.snd);

showCard (Pair ('A') ('♠'));
// => 'A♠'

showCard (Pair ('X') ('♠'));
// ! TypeError: Invalid value
//
//   showCard :: Pair Rank Suit -> String
//                    ^^^^
//                     1
//
//   1)  "X" :: String
//
//   The value at position 1 is not a member of ‘Rank’.
//
//   See http://example.com/my-package#Rank for information about the Rank type.

EnumType :: String -⁠> String -⁠> Array Any -⁠> Type

Конструктор типов для перечисляемых типов (таких как RegexFlags).

Для определения перечисляемого типа t необходимо предоставить:

  • название t (экспонировано как t.name);

  • ссылку на документацию t (экспонировано как t.url); и

  • массив различных значений.

Например:

//    Denomination :: Type
const Denomination = $.EnumType
  ('Denomination')
  ('http://example.com/my-package#Denomination')
  ([10, 20, 50, 100, 200]);

RecordType :: StrMap Type -⁠> Type

RecordType используется для построения анонимных типов записей. Определение типа указывает имя и тип каждого обязательного поля. Поле - это перечисляемое свойство (собственное свойство или унаследованное свойство).

Для определения анонимного типа записи необходимо предоставить:

  • объект, сопоставляющий имя поля с типом.

Например:

//    Point :: Type
const Point = $.RecordType ({x: $.FiniteNumber, y: $.FiniteNumber});

//    dist :: Point -> Point -> FiniteNumber
const dist =
def ('dist')
    ({})
    ([Point, Point, $.FiniteNumber])
    (p => q => Math.sqrt (Math.pow (p.x - q.x, 2) +
                          Math.pow (p.y - q.y, 2)));

dist ({x: 0, y: 0}) ({x: 3, y: 4});
// => 5

dist ({x: 0, y: 0}) ({x: 3, y: 4, color: 'red'});
// => 5

dist ({x: 0, y: 0}) ({x: NaN, y: NaN});
// ! TypeError: Invalid value
//
//   dist :: { x :: FiniteNumber, y :: FiniteNumber } -> { x :: FiniteNumber, y :: FiniteNumber } -> FiniteNumber
//                                                              ^^^^^^^^^^^^
//                                                                   1
//
//   1)  NaN :: Number
//
//   The value at position 1 is not a member of ‘FiniteNumber’.

dist (0);
// ! TypeError: Invalid value
//
//   dist :: { x :: FiniteNumber, y :: FiniteNumber } -> { x :: FiniteNumber, y :: FiniteNumber } -> FiniteNumber
//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                              1
//
//   1)  0 :: Number
//
//   The value at position 1 is not a member of ‘{ x :: FiniteNumber, y :: FiniteNumber }’.

NamedRecordType :: NonEmpty String -⁠> String -⁠> Array Type -⁠> StrMap Type -⁠> Type

NamedRecordType используется для построения именованных типов записей. Определение типа указывает имя и тип каждого обязательного поля. Поле - это перечисляемое свойство (собственное свойство или унаследованное свойство).

Для определения именованного типа записи t необходимо предоставить:

  • название t (экспонировано как t.name);

  • ссылку на документацию t (экспонировано как t.url);

  • массив супертипов (экспонировано как t.supertypes); и

  • объект, сопоставляющий имя поля с типом.

Например:

//    Circle :: Type
const Circle = $.NamedRecordType
  ('my-package/Circle')
  ('http://example.com/my-package#Circle')
  ([])
  ({radius: $.PositiveFiniteNumber});

//    Cylinder :: Type
const Cylinder = $.NamedRecordType
  ('Cylinder')
  ('http://example.com/my-package#Cylinder')
  ([Circle])
  ({height: $.PositiveFiniteNumber});

//    volume :: Cylinder -> PositiveFiniteNumber
const volume =
def ('volume')
    ({})
    ([Cylinder, $.FiniteNumber])
    (cyl => Math.PI * cyl.radius * cyl.radius * cyl.height);

volume ({radius: 2, height: 10});
// => 125.66370614359172

volume ({radius: 2});
// ! TypeError: Invalid value
//
//   volume :: Cylinder -> FiniteNumber
//             ^^^^^^^^
//                1
//
//   1)  {"radius": 2} :: Object, StrMap Number
//
//   The value at position 1 is not a member of ‘Cylinder’.
//
//   See http://example.com/my-package#Cylinder for information about the Cylinder type.

TypeVariable :: String -⁠> Type

Полиморфизм мощный. Неспособность определить функцию для всех типов была бы весьма ограничивающей: невозможно было бы даже определить функцию тождества!

Прежде чем определять полиморфную функцию, необходимо определить одну или несколько переменных типа:

const a = $.TypeVariable ('a');
const b = $.TypeVariable ('b');

//    id :: a -> a
const id = def ('id') ({}) ([a, a]) (x => x);

id (42);
// => 42

id (null);
// => null

Такая же переменная типа может использоваться в нескольких позициях, создавая ограничение:

//    cmp :: a -> a -> Number
const cmp =
def ('cmp')
    ({})
    ([a, a, $.Number])
    (x => y => x < y ? -1 : x > y ? 1 : 0);

cmp (42) (42);
// => 0

cmp ('a') ('z');
// => -1

cmp ('z') ('a');
// => 1

cmp (0) ('1');
// ! TypeError: Type-variable constraint violation
//
//   cmp :: a -> a -> Number
//          ^    ^
//          1    2
//
//   1)  0 :: Number
//
//   2)  "1" :: String
//
//   Since there is no type of which all the above values are members, the type-variable constraint has been violated.

UnaryTypeVariable :: String -⁠> Type -⁠> Type

Объединяет UnaryType и TypeVariable.

Для определения унарной переменной типа t a необходимо предоставить:

  • название (обычно совпадающее с ^[a-z]$); и

  • тип a.

Рассмотрим тип обобщенной map:

map :: Functor f => (a -> b) -> f a -> f b

f - это унарная переменная типа. С двумя (нулевыми) переменными типа, одной унарной переменной типа и одним классом типа можно определить полностью полиморфную map функцию:

const $ = require ('sanctuary-def');
const Z = require ('sanctuary-type-classes');

const a = $.TypeVariable ('a');
const b = $.TypeVariable ('b');
const f = $.UnaryTypeVariable ('f');

//    map :: Functor f => (a -> b) -> f a -> f b
const map =
def ('map')
    ({f: [Z.Functor]})
    ([$.Function ([a, b]), f (a), f (b)])
    (f => functor => Z.map (f, functor));

В то время как обычная переменная типа полностью разрешена (a может стать Array (Array String), например), унарная переменная типа ссылается на свой аргумент типа, который сам может быть переменной типа. Аргумент типа соответствует аргументу типа унарного типа или второму аргументу типа бинарного типа. Например, второй аргумент типа Map k v - это v. Можно заменить Functor => f на Map k или на Map Integer, но не на Map.

Это поверхностное исследование позволяет независимо ограничивать «внешние» и «внутренние» типы значения.

BinaryTypeVariable :: String -⁠> Type -⁠> Type -⁠> Type

Объединяет BinaryType и TypeVariable.

Для определения бинарной переменной типа t a b необходимо предоставить:

  • название (обычно совпадающее с ^[a-z]$);

  • тип a; и

  • тип b.

Более подробное объяснение UnaryTypeVariable также относится к BinaryTypeVariable.

Thunk :: Type -⁠> Type

$.Thunk (T) - это сокращение для $.Function ([T]), типа, включающего все нулевые функции (функции-задания), возвращающие значение типа T.

Predicate :: Type -⁠> Type

$.Predicate (T) — сокращение для $.Fn (T) ($.Boolean), типа, включающего каждую предикатную функцию, которая принимает значение типа T.

Классы типов

Можно тривиально определить функцию типа String -> String -> String, которая конкатенирует две строки. Однако это слишком ограничивает, так как другие типы также поддерживают конкатенацию (например, Array a).

Можно использовать переменную типа, чтобы определить полиморфную функцию «concat»:

//    _concat :: a -> a -> a
const _concat =
def ('_concat')
    ({})
    ([a, a, a])
    (x => y => x.concat (y));

_concat ('fizz') ('buzz');
// => 'fizzbuzz'

_concat ([1, 2]) ([3, 4]);
// => [1, 2, 3, 4]

_concat ([1, 2]) ('buzz');
// ! TypeError: Type-variable constraint violation
//
//   _concat :: a -> a -> a
//              ^    ^
//              1    2
//
//   1)  [1, 2] :: Array Number
//
//   2)  "buzz" :: String
//
//   Since there is no type of which all the above values are members, the type-variable constraint has been violated.

Тип _concat вводит в заблуждение: он предполагает, что он может работать с любыми двумя значениями любого одного типа. На самом деле есть неявное ограничение, так как тип должен поддерживать конкатенацию (в математических терминах, тип должен иметь полугруппу полугруппу). Нарушение этого неявного ограничения приводит к ошибке выполнения в реализации:

_concat (null) (null);
// ! TypeError: Cannot read property 'concat' of null

Решение состоит в том, чтобы ограничить a, сначала определив значение TypeClass, а затем указав ограничение в определении функции «concat»:

const Z = require ('sanctuary-type-classes');

//    Semigroup :: TypeClass
const Semigroup = Z.TypeClass (
  'my-package/Semigroup',
  'http://example.com/my-package#Semigroup',
  [],
  x => x != null && typeof x.concat === 'function'
);

//    concat :: Semigroup a => a -> a -> a
const concat =
def ('concat')
    ({a: [Semigroup]})
    ([a, a, a])
    (x => y => x.concat (y));

concat ([1, 2]) ([3, 4]);
// => [1, 2, 3, 4]

concat (null) (null);
// ! TypeError: Type-class constraint violation
//
//   concat :: Semigroup a => a -> a -> a
//             ^^^^^^^^^^^    ^
//                            1
//
//   1)  null :: Null
//
//   ‘concat’ requires ‘a’ to satisfy the Semigroup type-class constraint; the value at position 1 does not.
//
//   See http://example.com/my-package#Semigroup for information about the my-package/Semigroup type class.

Несколько ограничений можно применить к переменной типа, включив в массив несколько значений TypeClass (например, {a: [Foo, Bar, Baz]}).

© 2020 Sanctuary
© 2016 Plaid Technologies, Inc.
Licensed under the MIT License.
https://github.com/sanctuary-js/sanctuary-def/blob/v0.22.0/README.md

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API