Spec-Zone.ru › Sanctuary

Sanctuary v3.1.0

Убежище от небезопасного JavaScript

  • Обзор
  • Спонсоры
  • Folktale
  • Ramda
    • Полная определённость
    • Сохранение информации
    • Инварианты
    • Кэрринг
    • Функции с переменным числом аргументов
    • Неявный контекст
    • Трансдьюсеры
    • Модульность
  • Типы
  • Проверка типов
  • Установка
  • API

Обзор

Sanctuary — библиотека JavaScript для функционального программирования, вдохновлённая Haskell и PureScript. Она строже, чем Ramda, и предоставляет аналогичный набор функций.

Sanctuary способствует созданию программ, состоящих из простых чистых функций. Такие программы проще понять, протестировать и поддерживать — их также приятно писать.

Sanctuary предоставляет два типа данных, Maybe и Either, оба из которых совместимы с Fantasy Land. Благодаря этим типам данных даже функции Sanctuary, которые могут завершиться ошибкой, такие как head, являются композируемыми.

Sanctuary позволяет писать безопасный код без проверок на null. В JavaScript легко ввести потенциальную ошибку типа во время выполнения.

Sanctuary разработан для работы в Node.js и в браузерах, совместимых с ES5.

Спонсоры

Разработка Sanctuary финансируется следующими ориентированными на сообщество партнёрами:

  • Fink — небольшая, дружелюбная и страстная команда ИТ-консультантов. Мы любим то, что делаем, в основном это разработка веб- и мобильных приложений, включая графический дизайн, дизайн взаимодействия, разработку back-end и front-end, а также обеспечение того, что созданные вещи работают как задумано. Наша компания полностью принадлежит сотрудникам; мы придаём большое значение благополучию каждого сотрудника, как профессиональному, так и личному.

Разработка Sanctuary также поддерживается следующими щедрыми спонсорами:

  • @voxbono
  • @syves
  • @Avaq
  • @kabo
  • @o0th
  • @identinet

Стань спонсором, если хотите, чтобы экосистема Sanctuary стала ещё сильнее.

Folktale

Folktale, как и Sanctuary, является стандартной библиотекой функционального программирования на JavaScript. Она хорошо спроектирована и хорошо документирована. Если Sanctuary рассматривает JavaScript как язык семейства ML, Folktale охватывает объектно-ориентированную модель программирования JavaScript. Программирование с Folktale напоминает программирование со Scala.

Ramda

Ramda предоставляет несколько функций, которые возвращают проблемные значения, такие как undefined, Infinity, или NaN при применении к неподходящим входным данным. Эти функции называются частичными функциями. Частичные функции требуют использования защитных конструкций или проверок на null. Для безопасного использования R.head, например, необходимо убедиться, что массив не пуст:

if (R.isEmpty (xs)) {
  // ...
} else {
  return f (R.head (xs));
}

Использование типа Maybe делает такие защитные конструкции (и проверки на null) ненужными. Изменение функций, таких как R.head на возвращение значений типа Maybe было предложено в ramda/ramda#683, но было признано слишком сложным для разработчиков JavaScript. Sanctuary была выпущена на следующий месяц, в январе 2015 года, как дополнительная библиотека к Ramda.

Помимо расширения области применения за эти годы, философия Sanctuary в нескольких аспектах отличается от философии Ramda.

Полная определённость

Каждая функция Sanctuary определена для каждого значения, которое является членом входного типа функции. Такие функции называются полными функциями. Ramda, с другой стороны, содержит ряд частичных функций.

Сохранение информации

Определённые функции Sanctuary сохраняют больше информации, чем их аналоги из Ramda. Примеры:

|> R.tail ([])                      |> S.tail ([])
[]                                  Nothing

|> R.tail (['foo'])                 |> S.tail (['foo'])
[]                                  Just ([])

|> R.replace (/^x/) ('') ('abc')    |> S.stripPrefix ('x') ('abc')
'abc'                               Nothing

|> R.replace (/^x/) ('') ('xabc')   |> S.stripPrefix ('x') ('xabc')
'abc'                               Just ('abc')

Инварианты

Sanctuary выполняет строгую проверку типов входных и выходных данных и выводит описательную ошибку при обнаружении ошибки типа. Это позволяет обнаружить и исправить ошибки на ранней стадии жизненного цикла разработки.

Ramda работает по принципу «мусор на входе, мусор на выходе». Функции документированы так, чтобы принимать аргументы определённых типов, но эти инварианты не проверяются. Проблема такого подхода в языке, столь же допускающем ошибки, как JavaScript, заключается в том, что нет гарантии, что мусорный вход даст мусорный выход (ramda/ramda#1413). Ramda выполняет адоптивную проверку типов в некоторых таких случаях (ramda/ramda#1419).

Sanctuary можно настроить на работу в режиме «мусор на входе, мусор на выходе». Ramda не может быть настроена на проверку инвариантов.

Кэрринг

Функции Sanctuary кэрированы. Например, существует только один способ применить S.reduce к S.add, 0, и xs:

  • S.reduce (S.add) (0) (xs)

Функции Ramda также кэрированы, но сложным способом. Существует четыре способа применить R.reduce к R.add, 0, и xs:

  • R.reduce (R.add) (0) (xs)
  • R.reduce (R.add) (0, xs)
  • R.reduce (R.add, 0) (xs)
  • R.reduce (R.add, 0, xs)

Ramda поддерживает все эти формы, потому что кэрированные функции позволяют частичное применение, что является одним из принципов библиотеки, но f(x)(y)(z) считается слишком необычным и не достаточно привлекательным для разработчиков JavaScript.

Разработчики Sanctuary предпочитают простое, необычное решение сложному, привычному. Привычка может быть приобретена; сложность является внутренним свойством.

Недостаток свободного места в f(x)(y)(z) ухудшает читаемость. Простое решение этой проблемы, предложенное в #438, заключается в включении пробела при применении функции: f (x) (y) (z).

Ramda также предоставляет специальное значение-заполнитель, R.__, которое снимает ограничение на то, что функция должна быть применена к своим аргументам в определённом порядке. Следующие выражения эквивалентны:

  • R.reduce (R.__, 0, xs) (R.add)
  • R.reduce (R.add, R.__, xs) (0)
  • R.reduce (R.__, 0) (R.add) (xs)
  • R.reduce (R.__, 0) (R.add, xs)
  • R.reduce (R.__, R.__, xs) (R.add) (0)
  • R.reduce (R.__, R.__, xs) (R.add, 0)

Функции с переменным числом аргументов

Ramda предоставляет несколько функций, которые принимают любое количество аргументов. Эти функции называются функциями с переменным числом аргументов. Кроме того, Ramda предоставляет несколько функций, которые принимают функции с переменным числом аргументов в качестве аргументов. Хотя это естественно в динамически типизированном языке, функции с переменным числом аргументов противоречат системе обозначения типов, используемой Ramda и Sanctuary, что приводит к некоторым нечитаемым сигнатурам типов, например:

R.lift :: (*... -> *...) -> ([*]... -> [*])

В Sanctuary нет функций с переменным числом аргументов, и нет функций, которые принимают функции с переменным числом аргументов в качестве аргументов. Sanctuary предоставляет две функции «lift», каждая с полезной сигнатурой типа:

S.lift2 :: Apply f => (a -> b -> c) -> f a -> f b -> f c
S.lift3 :: Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d

Неявный контекст

Ramda предоставляет R.bind и R.invoker для работы с методами. Кроме того, многие функции Ramda используют Function#call или Function#apply для сохранения контекста. Sanctuary не поддерживает this.

Трансдьюсеры

Несколько функций Ramda действуют как трансдьюсеры. Sanctuary не поддерживает трансдьюсеры.

Модульность

В то время как у Ramda нет зависимостей, Sanctuary имеет модульную структуру: sanctuary-def обеспечивает проверку типов, sanctuary-type-classes предоставляет функции и типы классов Fantasy Land, sanctuary-show предоставляет строковые представления, а алгебраические типы данных предоставляются sanctuary-either, sanctuary-maybe и sanctuary-pair. Этот подход не только уменьшает сложность самого Sanctuary, но и позволяет повторно использовать эти компоненты в других контекстах.

Типы

Sanctuary использует схожие с Haskell сигнатуры типов для описания типов значений, включая функции. 'foo', например, является членом String; [1, 2, 3] является членом Array Number. Двойное двоеточие (::) используется для обозначения «является членом», поэтому можно написать:

'foo' :: String
[1, 2, 3] :: Array Number

Идентификатор может появляться слева от двойного двоеточия:

Math.PI :: Number

Стрелка (->) используется для выражения типа функции:

Math.abs :: Number -> Number

Это означает, что Math.abs — это унарная функция, которая принимает аргумент типа Number и возвращает значение типа Number.

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

S.I :: a -> a

a — это переменная типа. Переменные типов не пишутся с заглавной буквы, чтобы их можно было отличить от идентификаторов типов (которые всегда пишутся с заглавной буквы). По соглашению, переменные типов имеют имена из одной буквы. Приведённая выше сигнатура утверждает, что S.I принимает значение любого типа и возвращает значение того же типа. Некоторые сигнатуры содержат несколько переменных типов:

S.K :: a -> b -> a

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

Поскольку все функции Sanctuary являются каррированными (они принимают свои аргументы по одному), бинарная функция представлена как унарная функция, которая возвращает унарную функцию: * -> * -> *. Это идеально согласуется с Haskell, который использует исключительно каррированные функции. Однако в JavaScript нам может потребоваться представить типы функций с арностью меньше или больше единицы. Общий вид — (<input-types>) -> <output-type>, где <input-types> включает в себя ноль или более представлений типов, разделенных запятой и пробелом (, ) :

  • () -> String
  • (a, b) -> a
  • (a, b, c) -> d

Number -> Number таким образом можно рассматривать как сокращение для (Number) -> Number.

Sanctuary поддерживает типы. JavaScript не поддерживает алгебраические типы данных, но их можно смоделировать, предоставив группу конструкторов данных, которые возвращают значения с тем же набором методов. Например, значение типа Either создаётся с помощью конструктора Left или конструктора Right.

Необходимо расширить обозначение Haskell, чтобы описать неявные аргументы предоставляемых Sanctuary-типами методов. Например, в x.map(y), метод map принимает неявный аргумент x помимо явного аргумента y. Тип значения, к которому вызывается метод, отображается в начале подписи, разделённой от аргументов и возвращаемого значения волнистой стрелкой (~>). Тип метода fantasy-land/map типа Maybe записывается как Maybe a ~> (a -> b) -> Maybe b. Это можно прочитать как:

Когда метод fantasy-land/map вызывается для значения типа Maybe a (для любого типа a) с аргументом типа a -> b (для любого типа b), он возвращает значение типа Maybe b.

Волнистая стрелка также используется при представлении свойств, не являющихся функциями. Maybe a ~> Boolean, например, представляет булево свойство значения типа Maybe a.

Sanctuary поддерживает классы типов: ограничения на переменные типов. В то время как a -> a неявно поддерживает каждый тип, Functor f => (a -> b) -> f a -> f b требует, чтобы f был типом, который удовлетворяет требованиям класса типов Functor. Ограничения класса типов отображаются в начале подписи типа, разделённые от остальной подписи толстой стрелкой (=>).

Проверка типов

Функции Sanctuary определяются с помощью sanctuary-def для обеспечения проверки типов во время выполнения. Это очень полезно во время разработки: ошибки типов сообщаются немедленно, избегая запутанных стековых следов (в лучшем случае) и неявных ошибок из-за приведения типов (в худшем случае). Например:

> S.add (2) (true)
! Invalid value

add :: FiniteNumber -> FiniteNumber -> FiniteNumber
                       ^^^^^^^^^^^^
                            1

1)  true :: Boolean

The value at position 1 is not a member of ‘FiniteNumber’.

See https://github.com/sanctuary-js/sanctuary-def/tree/v0.22.0#FiniteNumber for information about the FiniteNumber type.

Сравните это с поведением не проверяемого эквивалента Ramda:

> R.add (2) (true)
3

Проверка типов во время выполнения имеет затраты на производительность. Проверка типов по умолчанию отключена, если process.env.NODE_ENV равно 'production'. Если это правило неприменимо для данной программы, можно использовать create для создания модуля Sanctuary на основе другого правила. Например:

const S = sanctuary.create ({
  checkTypes: localStorage.getItem ('SANCTUARY_CHECK_TYPES') === 'true',
  env: sanctuary.env,
});

Иногда может потребоваться выполнить операцию, которая не является безопасной с точки зрения типов, например, отобразить объект с неоднородными значениями. Это возможно с помощью выборочного использования функций unchecked.

Установка

npm install sanctuary установит Sanctuary для использования в Node.js.

Чтобы добавить Sanctuary на веб-сайт, добавьте следующий элемент <script>, заменив X.Y.Z на номер версии, не меньший, чем 2.0.2:

<script src="https://cdn.jsdelivr.net/gh/sanctuary-js/sanctuary@X.Y.Z/dist/bundle.js"></script>

Необязательно определить псевдонимы для различных модулей:

const S = window.sanctuary;
const $ = window.sanctuaryDef;
// ...

API

Настройка

create :: { checkTypes :: Boolean, env :: Array Type } -> Module

Принимает запись опций и возвращает модуль Sanctuary. checkTypes указывает, включена ли проверка типов. Полиморфные функции модуля (например, I) требуют, чтобы каждое значение, связанное с переменной типа, было членом по крайней мере одного типа в среде.

Хорошо типизированное применение функции Sanctuary даст тот же результат независимо от того, включена ли проверка типов. Если проверка типов включена, неправильно типизированное применение вызовет исключение с описательным сообщением об ошибке.

Следующий фрагмент демонстрирует определение пользовательского типа и использование create для создания модуля Sanctuary, который знает об этом типе:

const {create, env} = require ('sanctuary');
const $ = require ('sanctuary-def');
const type = require ('sanctuary-type-identifiers');

//    Identity :: a -> Identity a
const Identity = x => {
  const identity = Object.create (Identity$prototype);
  identity.value = x;
  return identity;
};

//    identityTypeIdent :: String
const identityTypeIdent = 'my-package/Identity@1';

const Identity$prototype = {
  '@@type': identityTypeIdent,
  '@@show': function() { return `Identity (${S.show (this.value)})`; },
  'fantasy-land/map': function(f) { return Identity (f (this.value)); },
};

//    IdentityType :: Type -> Type
const IdentityType = $.UnaryType
  ('Identity')
  ('http://example.com/my-package#Identity')
  ([])
  (x => type (x) === identityTypeIdent)
  (identity => [identity.value]);

const S = create ({
  checkTypes: process.env.NODE_ENV !== 'production',
  env: env.concat ([IdentityType ($.Unknown)]),
});

S.map (S.sub (1)) (Identity (43));
// => Identity (42)

См. также env.

env :: Array Type

Среда модуля Sanctuary ((S.create ({checkTypes, env})).env это ссылка на env). Полезно в сочетании с create.

> S.env
[Function, Arguments, Array Unknown, Array2 Unknown Unknown, Boolean, Buffer, Date, Descending Unknown, Either Unknown Unknown, Error, 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]

unchecked :: Module

Полный модуль Sanctuary, не выполняющий проверку типов. Это полезно, так как позволяет выполнять операции, которые проверка типов Sanctuary запретит, например, отображать объект с неоднородными значениями.

См. также create.

> S.unchecked.map (S.show) ({x: 'foo', y: true, z: 42})
{"x": "\"foo\"", "y": "true", "z": "42"}

Отказ от проверки типов может привести к тому, что ошибки типов останутся незамеченными.

> S.unchecked.add (2) ('2')
"22"

Классификация

type :: Any -> { namespace :: Maybe String, name :: String, version :: NonNegativeInteger }

Возвращает результат парсинга идентификатора типа идентификатора типа данного значения.

> S.type (S.Just (42))
{"name": "Maybe", "namespace": Just ("sanctuary-maybe"), "version": 1}

> S.type ([1, 2, 3])
{"name": "Array", "namespace": Nothing, "version": 0}

is :: Type -> Any -> Boolean

Возвращает true если и только если данное значение является членом указанного типа. Подробнее см. $.test.

> S.is ($.Array ($.Integer)) ([1, 2, 3])
true

> S.is ($.Array ($.Integer)) ([1, 2, 3.14])
false

Отображаемый

show :: Any -> String

Псевдоним show.

> S.show (-0)
"-0"

> S.show (['foo', 'bar', 'baz'])
"[\"foo\", \"bar\", \"baz\"]"

> S.show ({x: 1, y: 2, z: 3})
"{\"x\": 1, \"y\": 2, \"z\": 3}"

> S.show (S.Left (S.Right (S.Just (S.Nothing))))
"Left (Right (Just (Nothing)))"

Fantasy Land

Sanctuary совместим со спецификацией Fantasy Land.

equals :: Setoid a => a -> a -> Boolean

Каррированная версия Z.equals, которая требует два аргумента одного типа.

Для сравнения значений разных типов сначала используйте create для создания модуля Sanctuary с отключённой проверкой типов, а затем используйте функцию equals этого модуля.

> S.equals (0) (-0)
true

> S.equals (NaN) (NaN)
true

> S.equals (S.Just ([1, 2, 3])) (S.Just ([1, 2, 3]))
true

> S.equals (S.Just ([1, 2, 3])) (S.Just ([1, 2, 4]))
false

lt :: Ord a => a -> a -> Boolean

Возвращает true если и только если второй аргумент меньше первого в соответствии с Z.lt.

> S.filter (S.lt (3)) ([1, 2, 3, 4, 5])
[1, 2]

lte :: Ord a => a -> a -> Boolean

Возвращает true если и только если второй аргумент меньше или равен первому в соответствии с Z.lte.

> S.filter (S.lte (3)) ([1, 2, 3, 4, 5])
[1, 2, 3]

gt :: Ord a => a -> a -> Boolean

Возвращает true если и только если второй аргумент больше первого в соответствии с Z.gt.

> S.filter (S.gt (3)) ([1, 2, 3, 4, 5])
[4, 5]

gte :: Ord a => a -> a -> Boolean

Возвращает true если и только если второй аргумент больше или равен первому в соответствии с Z.gte.

> S.filter (S.gte (3)) ([1, 2, 3, 4, 5])
[3, 4, 5]

min :: Ord a => a -> a -> a

Возвращает меньший из двух аргументов (в соответствии с Z.lte).

См. также max.

> S.min (10) (2)
2

> S.min (new Date ('1999-12-31')) (new Date ('2000-01-01'))
new Date ("1999-12-31T00:00:00.000Z")

> S.min ('10') ('2')
"10"

max :: Ord a => a -> a -> a

Возвращает больший из двух аргументов (в соответствии с Z.lte).

См. также min.

> S.max (10) (2)
10

> S.max (new Date ('1999-12-31')) (new Date ('2000-01-01'))
new Date ("2000-01-01T00:00:00.000Z")

> S.max ('10') ('2')
"2"

clamp :: Ord a => a -> a -> a -> a

Принимает нижнюю границу, верхнюю границу и значение того же типа. Возвращает значение, если оно находится в границах; ближайшую границу в противном случае.

См. также min и max.

> S.clamp (0) (100) (42)
42

> S.clamp (0) (100) (-1)
0

> S.clamp ('A') ('Z') ('~')
"Z"

id :: Category c => TypeRep c -> c

Безопасная с точки зрения типов версия Z.id.

> S.id (Function) (42)
42

concat :: Semigroup a => a -> a -> a

Каррированная версия Z.concat.

> S.concat ('abc') ('def')
"abcdef"

> S.concat ([1, 2, 3]) ([4, 5, 6])
[1, 2, 3, 4, 5, 6]

> S.concat ({x: 1, y: 2}) ({y: 3, z: 4})
{"x": 1, "y": 3, "z": 4}

> S.concat (S.Just ([1, 2, 3])) (S.Just ([4, 5, 6]))
Just ([1, 2, 3, 4, 5, 6])

> S.concat (Sum (18)) (Sum (24))
Sum (42)

empty :: Monoid a => TypeRep a -> a

Безопасная с точки зрения типов версия Z.empty.

> S.empty (String)
""

> S.empty (Array)
[]

> S.empty (Object)
{}

> S.empty (Sum)
Sum (0)

invert :: Group g => g -> g

Безопасная с точки зрения типов версия Z.invert.

> S.invert (Sum (5))
Sum (-5)

filter :: Filterable f => (a -> Boolean) -> f a -> f a

Каррированная версия Z.filter. Отбрасывает каждый элемент, который не удовлетворяет предикату.

См. также reject.

> S.filter (S.odd) ([1, 2, 3])
[1, 3]

> S.filter (S.odd) ({x: 1, y: 2, z: 3})
{"x": 1, "z": 3}

> S.filter (S.odd) (S.Nothing)
Nothing

> S.filter (S.odd) (S.Just (0))
Nothing

> S.filter (S.odd) (S.Just (1))
Just (1)

reject :: Filterable f => (a -> Boolean) -> f a -> f a

Каррированная версия Z.reject. Отбрасывает каждый элемент, который удовлетворяет предикату.

См. также filter.

> S.reject (S.odd) ([1, 2, 3])
[2]

> S.reject (S.odd) ({x: 1, y: 2, z: 3})
{"y": 2}

> S.reject (S.odd) (S.Nothing)
Nothing

> S.reject (S.odd) (S.Just (0))
Just (0)

> S.reject (S.odd) (S.Just (1))
Nothing

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

Каррированная версия Z.map.

> S.map (Math.sqrt) ([1, 4, 9])
[1, 2, 3]

> S.map (Math.sqrt) ({x: 1, y: 4, z: 9})
{"x": 1, "y": 2, "z": 3}

> S.map (Math.sqrt) (S.Just (9))
Just (3)

> S.map (Math.sqrt) (S.Right (9))
Right (3)

> S.map (Math.sqrt) (S.Pair (99980001) (99980001))
Pair (99980001) (9999)

Замена Functor f => f на Function x даёт комбинатор B из комбинаторной логики (т.е. compose):

Functor f => (a -> b) -> f a -> f b
(a -> b) -> Function x a -> Function x b
(a -> c) -> Function x a -> Function x c
(b -> c) -> Function x b -> Function x c
(b -> c) -> Function a b -> Function a c
(b -> c) -> (a -> b) -> (a -> c)
> S.map (Math.sqrt) (S.add (1)) (99)
10

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

Каррированная версия Z.flip. Применяет каждую функцию к данному значению.

Замена Functor f => f на Function x даёт комбинатор C из комбинаторной логики:

Functor f => f (a -> b) -> a -> f b
Function x (a -> b) -> a -> Function x b
Function x (a -> c) -> a -> Function x c
Function x (b -> c) -> b -> Function x c
Function a (b -> c) -> b -> Function a c
(a -> b -> c) -> b -> a -> c
> S.flip (S.concat) ('!') ('foo')
"foo!"

> S.flip ([Math.floor, Math.ceil]) (1.5)
[1, 2]

> S.flip ({floor: Math.floor, ceil: Math.ceil}) (1.5)
{"ceil": 2, "floor": 1}

> S.flip (Cons (Math.floor) (Cons (Math.ceil) (Nil))) (1.5)
Cons (1) (Cons (2) (Nil))

bimap :: Bifunctor f => (a -> b) -> (c -> d) -> f a c -> f b d

Каррированная версия Z.bimap.

> S.bimap (S.toUpper) (Math.sqrt) (S.Pair ('foo') (64))
Pair ("FOO") (8)

> S.bimap (S.toUpper) (Math.sqrt) (S.Left ('foo'))
Left ("FOO")

> S.bimap (S.toUpper) (Math.sqrt) (S.Right (64))
Right (8)

mapLeft :: Bifunctor f => (a -> b) -> f a c -> f b c

Модифицированная версия Z.mapLeft. Применяет заданную функцию к левой части Бифунктора.

> S.mapLeft (S.toUpper) (S.Pair ('foo') (64))
Pair ("FOO") (64)

> S.mapLeft (S.toUpper) (S.Left ('foo'))
Left ("FOO")

> S.mapLeft (S.toUpper) (S.Right (64))
Right (64)

promap :: Profunctor p => (a -> b) -> (c -> d) -> p b c -> p a d

Модифицированная версия Z.promap.

> S.promap (Math.abs) (S.add (1)) (Math.sqrt) (-100)
11

alt :: Alt f => f a -> f a -> f a

Модифицированная версия Z.alt с переставленными аргументами для удобства частичного применения.

> S.alt (S.Just ('default')) (S.Nothing)
Just ("default")

> S.alt (S.Just ('default')) (S.Just ('hello'))
Just ("hello")

> S.alt (S.Right (0)) (S.Left ('X'))
Right (0)

> S.alt (S.Right (0)) (S.Right (1))
Right (1)

zero :: Plus f => TypeRep f -> f a

Безопасная версия Z.zero.

> S.zero (Array)
[]

> S.zero (Object)
{}

> S.zero (S.Maybe)
Nothing

reduce :: Foldable f => (b -> a -> b) -> b -> f a -> b

Принимает свёрнутую бинарную функцию, начальное значение и Foldable, применяет функцию к начальному значению и первому значению Foldable, затем к результату предыдущего применения и второму значению Foldable. Повторяет этот процесс, пока не будут использованы все значения Foldable. Возвращает начальное значение, если Foldable пусто; в противном случае, результат последнего применения.

См. также reduce_.

> S.reduce (S.add) (0) ([1, 2, 3, 4, 5])
15

> S.reduce (xs => x => S.prepend (x) (xs)) ([]) ([1, 2, 3, 4, 5])
[5, 4, 3, 2, 1]

reduce_ :: Foldable f => (a -> b -> b) -> b -> f a -> b

Вариант reduce с переставленными аргументами редуцирующей функции.

> S.reduce_ (S.append) ([]) (Cons (1) (Cons (2) (Cons (3) (Nil))))
[1, 2, 3]

> S.reduce_ (S.prepend) ([]) (Cons (1) (Cons (2) (Cons (3) (Nil))))
[3, 2, 1]

traverse :: (Applicative f, Traversable t) => TypeRep f -> (a -> f b) -> t a -> f (t b)

Модифицированная версия Z.traverse.

> S.traverse (Array) (S.words) (S.Just ('foo bar baz'))
[Just ("foo"), Just ("bar"), Just ("baz")]

> S.traverse (Array) (S.words) (S.Nothing)
[Nothing]

> S.traverse (S.Maybe) (S.parseInt (16)) (['A', 'B', 'C'])
Just ([10, 11, 12])

> S.traverse (S.Maybe) (S.parseInt (16)) (['A', 'B', 'C', 'X'])
Nothing

> S.traverse (S.Maybe) (S.parseInt (16)) ({a: 'A', b: 'B', c: 'C'})
Just ({"a": 10, "b": 11, "c": 12})

> S.traverse (S.Maybe) (S.parseInt (16)) ({a: 'A', b: 'B', c: 'C', x: 'X'})
Nothing

sequence :: (Applicative f, Traversable t) => TypeRep f -> t (f a) -> f (t a)

Модифицированная версия Z.sequence. Инвертирует заданный t (f a) для получения f (t a).

> S.sequence (Array) (S.Just ([1, 2, 3]))
[Just (1), Just (2), Just (3)]

> S.sequence (S.Maybe) ([S.Just (1), S.Just (2), S.Just (3)])
Just ([1, 2, 3])

> S.sequence (S.Maybe) ([S.Just (1), S.Just (2), S.Nothing])
Nothing

> S.sequence (S.Maybe) ({a: S.Just (1), b: S.Just (2), c: S.Just (3)})
Just ({"a": 1, "b": 2, "c": 3})

> S.sequence (S.Maybe) ({a: S.Just (1), b: S.Just (2), c: S.Nothing})
Nothing

ap :: Apply f => f (a -> b) -> f a -> f b

Модифицированная версия Z.ap.

> S.ap ([Math.sqrt, x => x * x]) ([1, 4, 9, 16, 25])
[1, 2, 3, 4, 5, 1, 16, 81, 256, 625]

> S.ap ({x: Math.sqrt, y: S.add (1), z: S.sub (1)}) ({w: 4, x: 4, y: 4})
{"x": 2, "y": 5}

> S.ap (S.Just (Math.sqrt)) (S.Just (64))
Just (8)

Замена Apply f => f на Function x даёт комбинатор S из комбинаторной логики:

Apply f => f (a -> b) -> f a -> f b
Function x (a -> b) -> Function x a -> Function x b
Function x (a -> c) -> Function x a -> Function x c
Function x (b -> c) -> Function x b -> Function x c
Function a (b -> c) -> Function a b -> Function a c
(a -> b -> c) -> (a -> b) -> (a -> c)
> S.ap (s => n => s.slice (0, n)) (s => Math.ceil (s.length / 2)) ('Haskell')
"Hask"

lift2 :: Apply f => (a -> b -> c) -> f a -> f b -> f c

Преобразует свёрнутую бинарную функцию в функцию, которая работает с двумя Apply.

> S.lift2 (S.add) (S.Just (2)) (S.Just (3))
Just (5)

> S.lift2 (S.add) (S.Just (2)) (S.Nothing)
Nothing

> S.lift2 (S.and) (S.Just (true)) (S.Just (true))
Just (true)

> S.lift2 (S.and) (S.Just (true)) (S.Just (false))
Just (false)

lift3 :: Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d

Преобразует свёрнутую тернарную функцию в функцию, которая работает с тремя Apply.

> S.lift3 (S.reduce) (S.Just (S.add)) (S.Just (0)) (S.Just ([1, 2, 3]))
Just (6)

> S.lift3 (S.reduce) (S.Just (S.add)) (S.Just (0)) (S.Nothing)
Nothing

apFirst :: Apply f => f a -> f b -> f a

Модифицированная версия Z.apFirst. Объединяет два эффектных действия, сохраняя только результат первого. Эквивалентно функции (<*) из Haskell.

См. также apSecond.

> S.apFirst ([1, 2]) ([3, 4])
[1, 1, 2, 2]

> S.apFirst (S.Just (1)) (S.Just (2))
Just (1)

apSecond :: Apply f => f a -> f b -> f b

Модифицированная версия Z.apSecond. Объединяет два эффектных действия, сохраняя только результат второго. Эквивалентно функции (*>) из Haskell.

См. также apFirst.

> S.apSecond ([1, 2]) ([3, 4])
[3, 4, 3, 4]

> S.apSecond (S.Just (1)) (S.Just (2))
Just (2)

of :: Applicative f => TypeRep f -> a -> f a

Модифицированная версия Z.of.

> S.of (Array) (42)
[42]

> S.of (Function) (42) (null)
42

> S.of (S.Maybe) (42)
Just (42)

> S.of (S.Either) (42)
Right (42)

chain :: Chain m => (a -> m b) -> m a -> m b

Модифицированная версия Z.chain.

> S.chain (x => [x, x]) ([1, 2, 3])
[1, 1, 2, 2, 3, 3]

> S.chain (n => s => s.slice (0, n)) (s => Math.ceil (s.length / 2)) ('slice')
"sli"

> S.chain (S.parseInt (10)) (S.Just ('123'))
Just (123)

> S.chain (S.parseInt (10)) (S.Just ('XXX'))
Nothing

join :: Chain m => m (m a) -> m a

Безопасная версия Z.join. Удаляет один уровень вложенности из вложенной монадической структуры.

> S.join ([[1], [2], [3]])
[1, 2, 3]

> S.join ([[[1, 2, 3]]])
[[1, 2, 3]]

> S.join (S.Just (S.Just (1)))
Just (1)

> S.join (S.Pair ('foo') (S.Pair ('bar') ('baz')))
Pair ("foobar") ("baz")

Замена Chain m => m на Function x даёт комбинатор W из комбинаторной логики:

Chain m => m (m a) -> m a
Function x (Function x a) -> Function x a
(x -> x -> a) -> (x -> a)
> S.join (S.concat) ('abc')
"abcabc"

chainRec :: ChainRec m => TypeRep m -> (a -> m (Either a b)) -> a -> m b

Выполняет вычисление, подобное chain, с постоянным объёмом стека. Аналогично Z.chainRec, но свёрнуто и удобнее благодаря использованию типа Either для обозначения завершения (через Right).

> S.chainRec (Array) (s => s.length === 2 ? S.map (S.Right) ([s + '!', s + '?']) : S.map (S.Left) ([s + 'o', s + 'n'])) ('')
["oo!", "oo?", "on!", "on?", "no!", "no?", "nn!", "nn?"]

extend :: Extend w => (w a -> b) -> w a -> w b

Модифицированная версия Z.extend.

> S.extend (S.joinWith ('')) (['x', 'y', 'z'])
["xyz", "yz", "z"]

> S.extend (f => f ([3, 4])) (S.reverse) ([1, 2])
[4, 3, 2, 1]

duplicate :: Extend w => w a -> w (w a)

Безопасная версия Z.duplicate. Добавляет один уровень вложенности в комонадическую структуру.

> S.duplicate (S.Just (1))
Just (Just (1))

> S.duplicate ([1])
[[1]]

> S.duplicate ([1, 2, 3])
[[1, 2, 3], [2, 3], [3]]

> S.duplicate (S.reverse) ([1, 2]) ([3, 4])
[4, 3, 2, 1]

extract :: Comonad w => w a -> a

Безопасная версия Z.extract.

> S.extract (S.Pair ('foo') ('bar'))
"bar"

contramap :: Contravariant f => (b -> a) -> f a -> f b

Безопасная версия Z.contramap.

> S.contramap (s => s.length) (Math.sqrt) ('Sanctuary')
3

Комбинатор

I :: a -> a

Комбинатор I. Возвращает свой аргумент. Эквивалентно функции id из Haskell.

> S.I ('foo')
"foo"

K :: a -> b -> a

Комбинатор K. Принимает два значения и возвращает первое. Эквивалентно функции const из Haskell.

> S.K ('foo') ('bar')
"foo"

> S.map (S.K (42)) (S.range (0) (5))
[42, 42, 42, 42, 42]

T :: a -> (a -> b) -> b

Комбинатор T (thrush). Принимает значение и функцию и возвращает результат применения функции к значению. Эквивалентно функции (&) из Haskell.

> S.T (42) (S.add (1))
43

> S.map (S.T (100)) ([S.add (1), Math.sqrt])
[101, 10]

Функция

curry2 :: ((a, b) -> c) -> a -> b -> c

Свёртывает заданную бинарную функцию.

> S.map (S.curry2 (Math.pow) (10)) ([1, 2, 3])
[10, 100, 1000]

curry3 :: ((a, b, c) -> d) -> a -> b -> c -> d

Свёртывает заданную тернарную функцию.

> const replaceString = S.curry3 ((what, replacement, string) => string.replace (what, replacement))
undefined

> replaceString ('banana') ('orange') ('banana icecream')
"orange icecream"

curry4 :: ((a, b, c, d) -> e) -> a -> b -> c -> d -> e

Свёртывает заданную кватернарную функцию.

> const createRect = S.curry4 ((x, y, width, height) => ({x, y, width, height}))
undefined

> createRect (0) (0) (10) (10)
{"height": 10, "width": 10, "x": 0, "y": 0}

curry5 :: ((a, b, c, d, e) -> f) -> a -> b -> c -> d -> e -> f

Свёртывает заданную квинарную функцию.

> const toUrl = S.curry5 ((protocol, creds, hostname, port, pathname) => protocol + '//' + S.maybe ('') (S.flip (S.concat) ('@')) (creds) + hostname + S.maybe ('') (S.concat (':')) (port) + pathname)
undefined

> toUrl ('https:') (S.Nothing) ('example.com') (S.Just ('443')) ('/foo/bar')
"https://example.com:443/foo/bar"

Композиция

compose :: Semigroupoid s => s b c -> s a b -> s a c

Модифицированная версия Z.compose.

При специализации на Function, compose композирует две унарные функции, справа налево (это комбинатор B из комбинаторной логики).

Обобщённая сигнатура типа указывает, что compose совместима с любым Semigroupoid.

См. также pipe.

> S.compose (Math.sqrt) (S.add (1)) (99)
10

pipe :: Foldable f => f (Any -> Any) -> a -> b

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

В общем случае pipe выполняет композицию последовательности функций слева направо. pipe ([f, g, h]) (x) эквивалентно h (g (f (x))).

> S.pipe ([S.add (1), Math.sqrt, S.sub (1)]) (99)
9

pipeK :: (Foldable f, Chain m) => f (Any -> m Any) -> m a -> m b

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

В общем случае pipeK выполняет левостороннюю композицию Клейсли последовательности функций. pipeK ([f, g, h]) (x) эквивалентно chain (h) (chain (g) (chain (f) (x))).

> S.pipeK ([S.tail, S.tail, S.head]) (S.Just ([1, 2, 3, 4]))
Just (3)

on :: (b -> b -> c) -> (a -> b) -> a -> a -> c

Принимает бинарную функцию f, унарную функцию g, и два значения x и y. Возвращает f (g (x)) (g (y)).

Это комбинатор P из комбинаторной логики.

> S.on (S.concat) (S.reverse) ([1, 2, 3]) ([4, 5, 6])
[3, 2, 1, 6, 5, 4]

Пара

Pair — это канонический тип произведения: значение типа Pair a b всегда содержит ровно два значения: одно типа a; одно типа b.

Реализация предоставлена sanctuary-pair.

Pair :: a -> b -> Pair a b

Единственный конструктор данных Pair. Кроме того, он служит представителем типа Pair type representative.

> S.Pair ('foo') (42)
Pair ("foo") (42)

pair :: (a -> b -> c) -> Pair a b -> c

Анализ случаев для типа Pair a b.

> S.pair (S.concat) (S.Pair ('foo') ('bar'))
"foobar"

fst :: Pair a b -> a

fst (Pair (x) (y)) эквивалентно x.

> S.fst (S.Pair ('foo') (42))
"foo"

snd :: Pair a b -> b

snd (Pair (x) (y)) эквивалентно y.

> S.snd (S.Pair ('foo') (42))
42

swap :: Pair a b -> Pair b a

swap (Pair (x) (y)) эквивалентно Pair (y) (x).

> S.swap (S.Pair ('foo') (42))
Pair (42) ("foo")

Maybe

Тип Maybe представляет необязательные значения: значение типа Maybe a это либо Nothing (пустое значение), либо Just, значение которого — типа a.

Реализация предоставлена sanctuary-maybe.

Maybe :: TypeRep Maybe

Представитель типа Maybe type representative.

Nothing :: Maybe a

Пустое значение типа Maybe a.

> S.Nothing
Nothing

Just :: a -> Maybe a

Создаёт значение типа Maybe a из значения типа a.

> S.Just (42)
Just (42)

isNothing :: Maybe a -> Boolean

Возвращает true если заданный Maybe равен Nothing; false если это Just.

> S.isNothing (S.Nothing)
true

> S.isNothing (S.Just (42))
false

isJust :: Maybe a -> Boolean

Возвращает true если заданный Maybe равен Just; false если это Nothing.

> S.isJust (S.Just (42))
true

> S.isJust (S.Nothing)
false

maybe :: b -> (a -> b) -> Maybe a -> b

Принимает значение любого типа, функцию и Maybe. Если Maybe равен Just, возвращаемое значение — результат применения функции к значению Just. В противном случае возвращается первый аргумент.

См. также maybe_ и fromMaybe.

> S.maybe (0) (S.prop ('length')) (S.Just ('refuge'))
6

> S.maybe (0) (S.prop ('length')) (S.Nothing)
0

maybe_ :: (() -> b) -> (a -> b) -> Maybe a -> b

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

> function fib(n) { return n <= 1 ? n : fib (n - 2) + fib (n - 1); }
undefined

> S.maybe_ (() => fib (30)) (Math.sqrt) (S.Just (1000000))
1000

> S.maybe_ (() => fib (30)) (Math.sqrt) (S.Nothing)
832040

fromMaybe :: a -> Maybe a -> a

Принимает значение по умолчанию и Maybe, и возвращает значение Maybe, если Maybe является Just; значение по умолчанию в противном случае.

См. также maybe, fromMaybe_ и maybeToNullable.

> S.fromMaybe (0) (S.Just (42))
42

> S.fromMaybe (0) (S.Nothing)
0

fromMaybe_ :: (() -> a) -> Maybe a -> a

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

> function fib(n) { return n <= 1 ? n : fib (n - 2) + fib (n - 1); }
undefined

> S.fromMaybe_ (() => fib (30)) (S.Just (1000000))
1000000

> S.fromMaybe_ (() => fib (30)) (S.Nothing)
832040

justs :: (Filterable f, Functor f) => f (Maybe a) -> f a

Отбрасывает каждый элемент, который является Nothing, и распаковывает каждый элемент, который является Just. Связано с функцией catMaybes в Haskell.

См. также lefts и rights.

> S.justs ([S.Just ('foo'), S.Nothing, S.Just ('baz')])
["foo", "baz"]

mapMaybe :: (Filterable f, Functor f) => (a -> Maybe b) -> f a -> f b

Принимает функцию и структуру, применяет функцию к каждому элементу структуры и возвращает результаты «успеха». Если результат применения функции к элементу — Nothing, результат отбрасывается; если результат — Just, значение Just включается.

> S.mapMaybe (S.head) ([[], [1, 2, 3], [], [4, 5, 6], []])
[1, 4]

> S.mapMaybe (S.head) ({x: [1, 2, 3], y: [], z: [4, 5, 6]})
{"x": 1, "z": 4}

maybeToNullable :: Maybe a -> Nullable a

Возвращает значение заданного Maybe, если Maybe — Just; null в противном случае. Nullable определено в sanctuary-def.

См. также fromMaybe.

> S.maybeToNullable (S.Just (42))
42

> S.maybeToNullable (S.Nothing)
null

maybeToEither :: a -> Maybe b -> Either a b

Преобразует Maybe в Either. Nothing становится Left (содержащим первый аргумент); Just становится Right.

См. также eitherToMaybe.

> S.maybeToEither ('Expecting an integer') (S.parseInt (10) ('xyz'))
Left ("Expecting an integer")

> S.maybeToEither ('Expecting an integer') (S.parseInt (10) ('42'))
Right (42)

Either

Тип Either представляет значения с двумя возможностями: значение типа Either a b является либо Left, значение которого имеет тип a, либо Right, значение которого имеет тип b.

Реализация предоставлена в sanctuary-either.

Either :: TypeRep Either

Either представитель типа.

Left :: a -> Either a b

Создаёт значение типа Either a b из значения типа a.

> S.Left ('Cannot divide by zero')
Left ("Cannot divide by zero")

Right :: b -> Either a b

Создаёт значение типа Either a b из значения типа b.

> S.Right (42)
Right (42)

isLeft :: Either a b -> Boolean

Возвращает true, если заданный Either — Left; false, если это Right.

> S.isLeft (S.Left ('Cannot divide by zero'))
true

> S.isLeft (S.Right (42))
false

isRight :: Either a b -> Boolean

Возвращает true, если заданный Either — Right; false, если это Left.

> S.isRight (S.Right (42))
true

> S.isRight (S.Left ('Cannot divide by zero'))
false

either :: (a -> c) -> (b -> c) -> Either a b -> c

Принимает две функции и Either, и возвращает результат применения первой функции к значению Left, если Either — Left, или результат применения второй функции к значению Right, если Either — Right.

См. также fromLeft и fromRight.

> S.either (S.toUpper) (S.show) (S.Left ('Cannot divide by zero'))
"CANNOT DIVIDE BY ZERO"

> S.either (S.toUpper) (S.show) (S.Right (42))
"42"

fromLeft :: a -> Either a b -> a

Принимает значение по умолчанию и Either, и возвращает значение Left, если Either — Left; значение по умолчанию в противном случае.

См. также either и fromRight.

> S.fromLeft ('abc') (S.Left ('xyz'))
"xyz"

> S.fromLeft ('abc') (S.Right (123))
"abc"

fromRight :: b -> Either a b -> b

Принимает значение по умолчанию и Either, и возвращает значение Right, если Either — Right; значение по умолчанию в противном случае.

См. также either и fromLeft.

> S.fromRight (123) (S.Right (789))
789

> S.fromRight (123) (S.Left ('abc'))
123

fromEither :: b -> Either a b -> b

Принимает значение по умолчанию и Either, и возвращает значение Right, если Either — Right; значение по умолчанию в противном случае.

Поведение fromEither может измениться в будущих версиях. Используйте fromRight вместо этого.

> S.fromEither (0) (S.Right (42))
42

> S.fromEither (0) (S.Left (42))
0

lefts :: (Filterable f, Functor f) => f (Either a b) -> f a

Отбрасывает каждый элемент, который является Right, и распаковывает каждый элемент, который является Left.

См. также rights.

> S.lefts ([S.Right (20), S.Left ('foo'), S.Right (10), S.Left ('bar')])
["foo", "bar"]

rights :: (Filterable f, Functor f) => f (Either a b) -> f b

Отбрасывает каждый элемент, который является Left, и распаковывает каждый элемент, который является Right.

См. также lefts.

> S.rights ([S.Right (20), S.Left ('foo'), S.Right (10), S.Left ('bar')])
[20, 10]

tagBy :: (a -> Boolean) -> a -> Either a a

Принимает предикат и значение, и возвращает Right значения, если оно удовлетворяет предикату; Left значения в противном случае.

> S.tagBy (S.odd) (0)
Left (0)

> S.tagBy (S.odd) (1)
Right (1)

encase :: Throwing e a b -> a -> Either e b

Принимает функцию, которая может генерировать исключение, и возвращает чистую функцию.

> S.encase (JSON.parse) ('["foo","bar","baz"]')
Right (["foo", "bar", "baz"])

> S.encase (JSON.parse) ('[')
Left (new SyntaxError ("Unexpected end of JSON input"))

eitherToMaybe :: Either a b -> Maybe b

Преобразует Either в Maybe. Left становится Nothing; Right становится Just.

См. также maybeToEither.

> S.eitherToMaybe (S.Left ('Cannot divide by zero'))
Nothing

> S.eitherToMaybe (S.Right (42))
Just (42)

Логика

and :: Boolean -> Boolean -> Boolean

Логическое «и».

> S.and (false) (false)
false

> S.and (false) (true)
false

> S.and (true) (false)
false

> S.and (true) (true)
true

or :: Boolean -> Boolean -> Boolean

Логическое «или».

> S.or (false) (false)
false

> S.or (false) (true)
true

> S.or (true) (false)
true

> S.or (true) (true)
true

not :: Boolean -> Boolean

Логическое «не».

См. также complement.

> S.not (false)
true

> S.not (true)
false

complement :: (a -> Boolean) -> a -> Boolean

Принимает унарный предикат и значение любого типа, и возвращает логическое отрицание применения предиката к значению.

См. также not.

> Number.isInteger (42)
true

> S.complement (Number.isInteger) (42)
false

boolean :: a -> a -> Boolean -> a

Анализ случая для типа Boolean. boolean (x) (y) (b) оценивается как x, если b имеет значение false; как y, если b имеет значение true.

> S.boolean ('no') ('yes') (false)
"no"

> S.boolean ('no') ('yes') (true)
"yes"

ifElse :: (a -> Boolean) -> (a -> b) -> (a -> b) -> a -> b

Принимает унарный предикат, унарную функцию «если», унарную функцию «иначе» и значение любого типа, и возвращает результат применения функции «если» к значению, если значение удовлетворяет предикату; результат применения функции «иначе» к значению в противном случае.

См. также when и unless.

> S.ifElse (x => x < 0) (Math.abs) (Math.sqrt) (-1)
1

> S.ifElse (x => x < 0) (Math.abs) (Math.sqrt) (16)
4

when :: (a -> Boolean) -> (a -> a) -> a -> a

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

См. также unless и ifElse.

> S.when (x => x >= 0) (Math.sqrt) (16)
4

> S.when (x => x >= 0) (Math.sqrt) (-1)
-1

unless :: (a -> Boolean) -> (a -> a) -> a -> a

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

См. также when и ifElse.

> S.unless (x => x < 0) (Math.sqrt) (16)
4

> S.unless (x => x < 0) (Math.sqrt) (-1)
-1

Массив

array :: b -> (a -> Array a -> b) -> Array a -> b

Анализ случая для типа Array a.

> S.array (S.Nothing) (head => tail => S.Just (head)) ([])
Nothing

> S.array (S.Nothing) (head => tail => S.Just (head)) ([1, 2, 3])
Just (1)

> S.array (S.Nothing) (head => tail => S.Just (tail)) ([])
Nothing

> S.array (S.Nothing) (head => tail => S.Just (tail)) ([1, 2, 3])
Just ([2, 3])

head :: Foldable f => f a -> Maybe a

Возвращает Just первого элемента заданной структуры, если структура содержит по меньшей мере один элемент; Nothing в противном случае.

> S.head ([1, 2, 3])
Just (1)

> S.head ([])
Nothing

> S.head (Cons (1) (Cons (2) (Cons (3) (Nil))))
Just (1)

> S.head (Nil)
Nothing

last :: Foldable f => f a -> Maybe a

Возвращает Just последнего элемента заданной структуры, если структура содержит по меньшей мере один элемент; Nothing в противном случае.

> S.last ([1, 2, 3])
Just (3)

> S.last ([])
Nothing

> S.last (Cons (1) (Cons (2) (Cons (3) (Nil))))
Just (3)

> S.last (Nil)
Nothing

tail :: (Applicative f, Foldable f, Monoid (f a)) => f a -> Maybe (f a)

Возвращает Just всех элементов структуры, кроме первого, если структура содержит по меньшей мере один элемент; Nothing в противном случае.

> S.tail ([1, 2, 3])
Just ([2, 3])

> S.tail ([])
Nothing

> S.tail (Cons (1) (Cons (2) (Cons (3) (Nil))))
Just (Cons (2) (Cons (3) (Nil)))

> S.tail (Nil)
Nothing

init :: (Applicative f, Foldable f, Monoid (f a)) => f a -> Maybe (f a)

Возвращает Just всех элементов структуры, кроме последнего, если структура содержит по меньшей мере один элемент; Nothing в противном случае.

> S.init ([1, 2, 3])
Just ([1, 2])

> S.init ([])
Nothing

> S.init (Cons (1) (Cons (2) (Cons (3) (Nil))))
Just (Cons (1) (Cons (2) (Nil)))

> S.init (Nil)
Nothing

take :: (Applicative f, Foldable f, Monoid (f a)) => Integer -> f a -> Maybe (f a)

Возвращает Just первых N элементов заданной структуры, если N неотрицательно и меньше или равно размеру структуры; Nothing в противном случае.

> S.take (0) (['foo', 'bar'])
Just ([])

> S.take (1) (['foo', 'bar'])
Just (["foo"])

> S.take (2) (['foo', 'bar'])
Just (["foo", "bar"])

> S.take (3) (['foo', 'bar'])
Nothing

> S.take (3) (Cons (1) (Cons (2) (Cons (3) (Cons (4) (Cons (5) (Nil))))))
Just (Cons (1) (Cons (2) (Cons (3) (Nil))))

drop :: (Applicative f, Foldable f, Monoid (f a)) => Integer -> f a -> Maybe (f a)

Возвращает Just всех элементов структуры, кроме первых N, если N неотрицательно и меньше или равно размеру структуры; Nothing в противном случае.

> S.drop (0) (['foo', 'bar'])
Just (["foo", "bar"])

> S.drop (1) (['foo', 'bar'])
Just (["bar"])

> S.drop (2) (['foo', 'bar'])
Just ([])

> S.drop (3) (['foo', 'bar'])
Nothing

> S.drop (3) (Cons (1) (Cons (2) (Cons (3) (Cons (4) (Cons (5) (Nil))))))
Just (Cons (4) (Cons (5) (Nil)))

takeLast :: (Applicative f, Foldable f, Monoid (f a)) => Integer -> f a -> Maybe (f a)

Возвращает Just последних N элементов заданной структуры, если N неотрицательно и меньше или равно размеру структуры; Nothing в противном случае.

> S.takeLast (0) (['foo', 'bar'])
Just ([])

> S.takeLast (1) (['foo', 'bar'])
Just (["bar"])

> S.takeLast (2) (['foo', 'bar'])
Just (["foo", "bar"])

> S.takeLast (3) (['foo', 'bar'])
Nothing

> S.takeLast (3) (Cons (1) (Cons (2) (Cons (3) (Cons (4) (Nil)))))
Just (Cons (2) (Cons (3) (Cons (4) (Nil))))

dropLast :: (Applicative f, Foldable f, Monoid (f a)) => Integer -> f a -> Maybe (f a)

Возвращает Just всех элементов структуры, кроме последних N, если N неотрицательно и меньше или равно размеру структуры; Nothing в противном случае.

> S.dropLast (0) (['foo', 'bar'])
Just (["foo", "bar"])

> S.dropLast (1) (['foo', 'bar'])
Just (["foo"])

> S.dropLast (2) (['foo', 'bar'])
Just ([])

> S.dropLast (3) (['foo', 'bar'])
Nothing

> S.dropLast (3) (Cons (1) (Cons (2) (Cons (3) (Cons (4) (Nil)))))
Just (Cons (1) (Nil))

takeWhile :: (a -> Boolean) -> Array a -> Array a

Отбрасывает первый элемент, который не удовлетворяет предикату, и все последующие элементы.

См. также dropWhile.

> S.takeWhile (S.odd) ([3, 3, 3, 7, 6, 3, 5, 4])
[3, 3, 3, 7]

> S.takeWhile (S.even) ([3, 3, 3, 7, 6, 3, 5, 4])
[]

dropWhile :: (a -> Boolean) -> Array a -> Array a

Сохраняет первый элемент, который не удовлетворяет предикату, и все последующие элементы.

См. также takeWhile.

> S.dropWhile (S.odd) ([3, 3, 3, 7, 6, 3, 5, 4])
[6, 3, 5, 4]

> S.dropWhile (S.even) ([3, 3, 3, 7, 6, 3, 5, 4])
[3, 3, 3, 7, 6, 3, 5, 4]

size :: Foldable f => f a -> NonNegativeInteger

Возвращает количество элементов заданной структуры.

> S.size ([])
0

> S.size (['foo', 'bar', 'baz'])
3

> S.size (Nil)
0

> S.size (Cons ('foo') (Cons ('bar') (Cons ('baz') (Nil))))
3

> S.size (S.Nothing)
0

> S.size (S.Just ('quux'))
1

> S.size (S.Pair ('ignored!') ('counted!'))
1

all :: Foldable f => (a -> Boolean) -> f a -> Boolean

Возвращает true если и только если все элементы структуры удовлетворяют предикату.

См. также any и none.

> S.all (S.odd) ([])
true

> S.all (S.odd) ([1, 3, 5])
true

> S.all (S.odd) ([1, 2, 3])
false

any :: Foldable f => (a -> Boolean) -> f a -> Boolean

Возвращает true если и только если какой-либо элемент структуры удовлетворяет предикату.

См. также all и none.

> S.any (S.odd) ([])
false

> S.any (S.odd) ([2, 4, 6])
false

> S.any (S.odd) ([1, 2, 3])
true

none :: Foldable f => (a -> Boolean) -> f a -> Boolean

Возвращает true если и только если ни один из элементов структуры не удовлетворяет предикату.

Свойства:

  • forall p :: a -> Boolean, xs :: Foldable f => f a. S.none (p) (xs) = S.not (S.any (p) (xs))

  • forall p :: a -> Boolean, xs :: Foldable f => f a. S.none (p) (xs) = S.all (S.complement (p)) (xs)

См. также all и any.

> S.none (S.odd) ([])
true

> S.none (S.odd) ([2, 4, 6])
true

> S.none (S.odd) ([1, 2, 3])
false

append :: (Applicative f, Semigroup (f a)) => a -> f a -> f a

Возвращает результат присоединения первого аргумента ко второму.

См. также prepend.

> S.append (3) ([1, 2])
[1, 2, 3]

> S.append (3) (Cons (1) (Cons (2) (Nil)))
Cons (1) (Cons (2) (Cons (3) (Nil)))

> S.append ([1]) (S.Nothing)
Just ([1])

> S.append ([3]) (S.Just ([1, 2]))
Just ([1, 2, 3])

prepend :: (Applicative f, Semigroup (f a)) => a -> f a -> f a

Возвращает результат добавления первого аргумента в начало второго.

См. также append.

> S.prepend (1) ([2, 3])
[1, 2, 3]

> S.prepend (1) (Cons (2) (Cons (3) (Nil)))
Cons (1) (Cons (2) (Cons (3) (Nil)))

> S.prepend ([1]) (S.Nothing)
Just ([1])

> S.prepend ([1]) (S.Just ([2, 3]))
Just ([1, 2, 3])

joinWith :: String -> Array String -> String

Объединяет строки второго аргумента, разделённые первым аргументом.

Свойства:

  • forall s :: String, t :: String. S.joinWith (s) (S.splitOn (s) (t)) = t

См. также splitOn и intercalate.

> S.joinWith (':') (['foo', 'bar', 'baz'])
"foo:bar:baz"

elem :: (Setoid a, Foldable f) => a -> f a -> Boolean

Принимает значение и структуру, и возвращает true если и только если значение является элементом структуры.

См. также find.

> S.elem ('c') (['a', 'b', 'c'])
true

> S.elem ('x') (['a', 'b', 'c'])
false

> S.elem (3) ({x: 1, y: 2, z: 3})
true

> S.elem (8) ({x: 1, y: 2, z: 3})
false

> S.elem (0) (S.Just (0))
true

> S.elem (0) (S.Just (1))
false

> S.elem (0) (S.Nothing)
false

find :: Foldable f => (a -> Boolean) -> f a -> Maybe a

Принимает предикат и структуру и возвращает Just самое левое элемент структуры, удовлетворяющее предикату; Nothing, если такого элемента нет.

См. также elem.

> S.find (S.lt (0)) ([1, -2, 3, -4, 5])
Just (-2)

> S.find (S.lt (0)) ([1, 2, 3, 4, 5])
Nothing

intercalate :: (Monoid m, Foldable f) => m -> f m -> m

Частичная версия Z.intercalate. Объединяет элементы заданной структуры, разделяя каждую пару смежных элементов заданным разделителем.

См. также joinWith.

> S.intercalate (', ') ([])
""

> S.intercalate (', ') (['foo', 'bar', 'baz'])
"foo, bar, baz"

> S.intercalate (', ') (Nil)
""

> S.intercalate (', ') (Cons ('foo') (Cons ('bar') (Cons ('baz') (Nil))))
"foo, bar, baz"

> S.intercalate ([0, 0, 0]) ([])
[]

> S.intercalate ([0, 0, 0]) ([[1], [2, 3], [4, 5, 6], [7, 8], [9]])
[1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 8, 0, 0, 0, 9]

foldMap :: (Monoid m, Foldable f) => TypeRep m -> (a -> m) -> f a -> m

Частичная версия Z.foldMap. Разбирает сворачиваемый объект, отображая каждый элемент в моноид и объединяя результаты.

> S.foldMap (String) (f => f.name) ([Math.sin, Math.cos, Math.tan])
"sincostan"

> S.foldMap (Array) (x => [x + 1, x + 2]) ([10, 20, 30])
[11, 12, 21, 22, 31, 32]

unfoldr :: (b -> Maybe (Pair a b)) -> b -> Array a

Принимает функцию и начальное значение и возвращает массив, генерируемый многократным применением функции. Массив изначально пустой. Функция изначально применяется к начальному значению. Каждое применение функции должно привести к:

  • Nothing, в этом случае возвращается массив; или

  • Just пара, в этом случае первый элемент добавляется в массив, а функция применяется ко второму элементу.

> S.unfoldr (n => n < 1000 ? S.Just (S.Pair (n) (2 * n)) : S.Nothing) (1)
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

range :: Integer -> Integer -> Array Integer

Возвращает массив последовательных целых чисел, начиная с первого аргумента и заканчивая вторым аргументом минус один. Возвращает [] если второй аргумент меньше или равен первому аргументу.

> S.range (0) (10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

> S.range (-5) (0)
[-5, -4, -3, -2, -1]

> S.range (0) (-5)
[]

groupBy :: (a -> a -> Boolean) -> Array a -> Array (Array a)

Разбивает свой аргумент-массив на массив массивов одинаковых, смежных элементов. Равенство определяется функцией, предоставленной в качестве первого аргумента. Его поведение может быть неожиданным для функций, которые не являются рефлексивными, транзитивными и симметричными (см. отношение эквивалентности).

Свойства:

  • forall f :: a -> a -> Boolean, xs :: Array a. S.join (S.groupBy (f) (xs)) = xs
> S.groupBy (S.equals) ([1, 1, 2, 1, 1])
[[1, 1], [2], [1, 1]]

> S.groupBy (x => y => x + y === 0) ([2, -3, 3, 3, 3, 4, -4, 4])
[[2], [-3, 3, 3, 3], [4, -4], [4]]

reverse :: (Applicative f, Foldable f, Monoid (f a)) => f a -> f a

Инвертирует элементы заданной структуры.

> S.reverse ([1, 2, 3])
[3, 2, 1]

> S.reverse (Cons (1) (Cons (2) (Cons (3) (Nil))))
Cons (3) (Cons (2) (Cons (1) (Nil)))

> S.pipe ([S.splitOn (''), S.reverse, S.joinWith ('')]) ('abc')
"cba"

sort :: (Ord a, Applicative m, Foldable m, Monoid (m a)) => m a -> m a

Выполняет стабильную сортировку элементов заданной структуры, используя Z.lte для сравнения.

Свойства:

  • S.sort (S.sort (m)) = S.sort (m) (идемпотентность)

См. также sortBy.

> S.sort (['foo', 'bar', 'baz'])
["bar", "baz", "foo"]

> S.sort ([S.Left (4), S.Right (3), S.Left (2), S.Right (1)])
[Left (2), Left (4), Right (1), Right (3)]

sortBy :: (Ord b, Applicative m, Foldable m, Monoid (m a)) => (a -> b) -> m a -> m a

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

Свойства:

  • S.sortBy (f) (S.sortBy (f) (m)) = S.sortBy (f) (m) (идемпотентность)

См. также sort.

> S.sortBy (S.prop ('rank')) ([{rank: 7, suit: 'spades'}, {rank: 5, suit: 'hearts'}, {rank: 2, suit: 'hearts'}, {rank: 5, suit: 'spades'}])
[{"rank": 2, "suit": "hearts"}, {"rank": 5, "suit": "hearts"}, {"rank": 5, "suit": "spades"}, {"rank": 7, "suit": "spades"}]

> S.sortBy (S.prop ('suit')) ([{rank: 7, suit: 'spades'}, {rank: 5, suit: 'hearts'}, {rank: 2, suit: 'hearts'}, {rank: 5, suit: 'spades'}])
[{"rank": 5, "suit": "hearts"}, {"rank": 2, "suit": "hearts"}, {"rank": 7, "suit": "spades"}, {"rank": 5, "suit": "spades"}]

Если требуется сортировка по убыванию, можно использовать Descending:

> S.sortBy (Descending) ([83, 97, 110, 99, 116, 117, 97, 114, 121])
[121, 117, 116, 114, 110, 99, 97, 97, 83]

zip :: Array a -> Array b -> Array (Pair a b)

Возвращает массив пар соответствующих элементов из заданных массивов. Длина результирующего массива равна длине самого короткого входного массива.

См. также zipWith.

> S.zip (['a', 'b']) (['x', 'y', 'z'])
[Pair ("a") ("x"), Pair ("b") ("y")]

> S.zip ([1, 3, 5]) ([2, 4])
[Pair (1) (2), Pair (3) (4)]

zipWith :: (a -> b -> c) -> Array a -> Array b -> Array c

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

См. также zip.

> S.zipWith (a => b => a + b) (['a', 'b']) (['x', 'y', 'z'])
["ax", "by"]

> S.zipWith (a => b => [a, b]) ([1, 3, 5]) ([2, 4])
[[1, 2], [3, 4]]

Объект

prop :: String -> a -> b

Принимает имя свойства и объект с известными свойствами и возвращает значение указанного свойства. Если по какой-либо причине у объекта отсутствует указанное свойство, генерируется ошибка типа.

Для доступа к свойствам неопределённых объектов используйте get вместо. Для доступа к значениям строковой карты по ключу используйте value вместо.

> S.prop ('a') ({a: 1, b: 2})
1

props :: Array String -> a -> b

Принимает путь к свойству (массив имён свойств) и объект с известной структурой и возвращает значение по указанному пути. Если по какой-либо причине путь не существует, генерируется ошибка типа.

Для доступа к путям свойств неопределённых объектов используйте gets вместо.

> S.props (['a', 'b', 'c']) ({a: {b: {c: 1}}})
1

get :: (Any -> Boolean) -> String -> a -> Maybe b

Принимает предикат, имя свойства и объект и возвращает Just значение указанного свойства объекта, если оно существует и значение удовлетворяет заданному предикату; Nothing в противном случае.

См. также gets, prop и value.

> S.get (S.is ($.Number)) ('x') ({x: 1, y: 2})
Just (1)

> S.get (S.is ($.Number)) ('x') ({x: '1', y: '2'})
Nothing

> S.get (S.is ($.Number)) ('x') ({})
Nothing

> S.get (S.is ($.Array ($.Number))) ('x') ({x: [1, 2, 3]})
Just ([1, 2, 3])

> S.get (S.is ($.Array ($.Number))) ('x') ({x: [1, 2, 3, null]})
Nothing

gets :: (Any -> Boolean) -> Array String -> a -> Maybe b

Принимает предикат, путь к свойству (массив имён свойств) и объект и возвращает Just значение по заданному пути, если такой путь существует и значение удовлетворяет заданному предикату; Nothing в противном случае.

См. также get.

> S.gets (S.is ($.Number)) (['a', 'b', 'c']) ({a: {b: {c: 42}}})
Just (42)

> S.gets (S.is ($.Number)) (['a', 'b', 'c']) ({a: {b: {c: '42'}}})
Nothing

> S.gets (S.is ($.Number)) (['a', 'b', 'c']) ({})
Nothing

StrMap

StrMap — аббревиатура от строковой карты. Строковая карта — это объект, такой как {foo: 1, bar: 2, baz: 3}, значения которого являются членами одного и того же типа. Строго говоря, значение является членом типа StrMap a если его идентификатор типа равен 'Object', а значения его перечисляемых собственных свойств являются членами типа a.

value :: String -> StrMap a -> Maybe a

Извлечь значение, связанное с данным ключом в данной строковой карте.

Строго говоря, value (k) (m) вычисляет Just (m[k]) если k является перечисляемым собственным свойством m; Nothing в противном случае.

См. также prop и get.

> S.value ('foo') ({foo: 1, bar: 2})
Just (1)

> S.value ('bar') ({foo: 1, bar: 2})
Just (2)

> S.value ('baz') ({foo: 1, bar: 2})
Nothing

singleton :: String -> a -> StrMap a

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

> S.singleton ('foo') (42)
{"foo": 42}

insert :: String -> a -> StrMap a -> StrMap a

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

Эквивалентно функции Haskell's insert . Аналогично функции Clojure's assoc.

> S.insert ('c') (3) ({a: 1, b: 2})
{"a": 1, "b": 2, "c": 3}

> S.insert ('a') (4) ({a: 1, b: 2})
{"a": 4, "b": 2}

remove :: String -> StrMap a -> StrMap a

Принимает строку и строковую карту и возвращает строковую карту, содержащую все записи данной строковой карты, кроме той, ключ которой совпадает с данной строкой (если такой ключ существует).

Эквивалентно функции Haskell's delete . Аналогично функции Clojure's dissoc.

> S.remove ('c') ({a: 1, b: 2, c: 3})
{"a": 1, "b": 2}

> S.remove ('c') ({})
{}

keys :: StrMap a -> Array String

Возвращает ключи данной строковой карты в произвольном порядке.

> S.sort (S.keys ({b: 2, c: 3, a: 1}))
["a", "b", "c"]

values :: StrMap a -> Array a

Возвращает значения данной строковой карты в произвольном порядке.

> S.sort (S.values ({a: 1, c: 3, b: 2}))
[1, 2, 3]

pairs :: StrMap a -> Array (Pair String a)

Возвращает пары ключ-значение данной строковой карты в произвольном порядке.

> S.sort (S.pairs ({b: 2, a: 1, c: 3}))
[Pair ("a") (1), Pair ("b") (2), Pair ("c") (3)]

fromPairs :: Foldable f => f (Pair String a) -> StrMap a

Возвращает строковую карту, содержащую пары ключ-значение, указанные данным Foldable. Если ключ встречается в нескольких парах, имеет приоритет правая пара.

> S.fromPairs ([S.Pair ('a') (1), S.Pair ('b') (2), S.Pair ('c') (3)])
{"a": 1, "b": 2, "c": 3}

> S.fromPairs ([S.Pair ('x') (1), S.Pair ('x') (2)])
{"x": 2}

Число

negate :: ValidNumber -> ValidNumber

Изменяет знак своего аргумента.

> S.negate (12.5)
-12.5

> S.negate (-42)
42

add :: FiniteNumber -> FiniteNumber -> FiniteNumber

Возвращает сумму двух (конечных) чисел.

> S.add (1) (1)
2

sum :: Foldable f => f FiniteNumber -> FiniteNumber

Возвращает сумму данного массива (конечных) чисел.

> S.sum ([1, 2, 3, 4, 5])
15

> S.sum ([])
0

> S.sum (S.Just (42))
42

> S.sum (S.Nothing)
0

sub :: FiniteNumber -> FiniteNumber -> FiniteNumber

Принимает конечное число n и возвращает функцию вычитания n.

> S.map (S.sub (1)) ([1, 2, 3])
[0, 1, 2]

mult :: FiniteNumber -> FiniteNumber -> FiniteNumber

Возвращает произведение двух (конечных) чисел.

> S.mult (4) (2)
8

product :: Foldable f => f FiniteNumber -> FiniteNumber

Возвращает произведение данного массива (конечных) чисел.

> S.product ([1, 2, 3, 4, 5])
120

> S.product ([])
1

> S.product (S.Just (42))
42

> S.product (S.Nothing)
1

div :: NonZeroFiniteNumber -> FiniteNumber -> FiniteNumber

Принимает ненулевое конечное число n и возвращает функцию деления на n.

> S.map (S.div (2)) ([0, 1, 2, 3])
[0, 0.5, 1, 1.5]

pow :: FiniteNumber -> FiniteNumber -> FiniteNumber

Принимает конечное число n и возвращает функцию возведения в степень n.

> S.map (S.pow (2)) ([-3, -2, -1, 0, 1, 2, 3])
[9, 4, 1, 0, 1, 4, 9]

> S.map (S.pow (0.5)) ([1, 4, 9, 16, 25])
[1, 2, 3, 4, 5]

mean :: Foldable f => f FiniteNumber -> Maybe FiniteNumber

Возвращает среднее значение данного массива (конечных) чисел.

> S.mean ([1, 2, 3, 4, 5])
Just (3)

> S.mean ([])
Nothing

> S.mean (S.Just (42))
Just (42)

> S.mean (S.Nothing)
Nothing

Целое число

even :: Integer -> Boolean

Возвращает true если данное целое число чётное; false если оно нечётное.

> S.even (42)
true

> S.even (99)
false

odd :: Integer -> Boolean

Возвращает true если данное целое число нечётное; false если оно чётное.

> S.odd (99)
true

> S.odd (42)
false

Парсинг

parseDate :: String -> Maybe ValidDate

Принимает строку s и возвращает Just (new Date (s)) если new Date (s) вычисляется как значение ValidDate; Nothing в противном случае.

Как отмечено в #488, поведение этой функции не определено для некоторых входных данных! MDN предупреждает против использования конструктора Date для парсинга строк дат:

Примечание: парсинг строк дат с помощью конструктора Date […] категорически не рекомендуется из-за различий и несоответствий в браузерах. Поддержка форматов строк RFC 2822 носит лишь условный характер. Поддержка форматов ISO 8601 различается: строки только с датой (например, "1970-01-01") обрабатываются как UTC, а не локально.

> S.parseDate ('2011-01-19T17:40:00Z')
Just (new Date ("2011-01-19T17:40:00.000Z"))

> S.parseDate ('today')
Nothing

parseFloat :: String -> Maybe Number

Принимает строку и возвращает Just число, представленное строкой, если оно действительно представляет собой число; Nothing в противном случае.

> S.parseFloat ('-123.45')
Just (-123.45)

> S.parseFloat ('foo.bar')
Nothing

parseInt :: Radix -> String -> Maybe Integer

Принимает основание (целое число от 2 до 36 включительно) и строку и возвращает Just число, представленное строкой, если оно действительно представляет собой число в системе счисления, заданной основанием; Nothing в противном случае.

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

> S.parseInt (10) ('-42')
Just (-42)

> S.parseInt (16) ('0xFF')
Just (255)

> S.parseInt (16) ('0xGG')
Nothing

parseJson :: (Any -> Boolean) -> String -> Maybe a

Принимает предикат и строку, которая может быть или не быть валидным JSON, и возвращает результат применения JSON.parse к строке если результат удовлетворяет предикату; в противном случае возвращает Nothing.

> S.parseJson (S.is ($.Array ($.Integer))) ('[')
Nothing

> S.parseJson (S.is ($.Array ($.Integer))) ('["1","2","3"]')
Nothing

> S.parseJson (S.is ($.Array ($.Integer))) ('[0,1.5,3,4.5]')
Nothing

> S.parseJson (S.is ($.Array ($.Integer))) ('[1,2,3]')
Just ([1, 2, 3])

Регулярные выражения

regex :: RegexFlags -> String -> RegExp

Принимает RegexFlags и шаблон, и возвращает RegExp.

> S.regex ('g') (':\\d+:')
/:\d+:/g

regexEscape :: String -> String

Принимает строку, которая может содержать метасимволы регулярных выражений, и возвращает строку с этими метасимволами экранированными.

Свойства:

  • forall s :: String. S.test (S.regex ('') (S.regexEscape (s))) (s) = true
> S.regexEscape ('-=*{XYZ}*=-')
"\\-=\\*\\{XYZ\\}\\*=\\-"

test :: RegExp -> String -> Boolean

Принимает шаблон и строку, и возвращает true если шаблон соответствует строке.

> S.test (/^a/) ('abacus')
true

> S.test (/^a/) ('banana')
false

match :: NonGlobalRegExp -> String -> Maybe { match :: String, groups :: Array (Maybe String) }

Принимает шаблон и строку, и возвращает Just запись совпадения, если шаблон соответствует строке; в противном случае возвращает Nothing.

groups :: Array (Maybe String) учитывает существование необязательных групп захвата.

Свойства:

  • forall p :: Pattern, s :: String. S.head (S.matchAll (S.regex ('g') (p)) (s)) = S.match (S.regex ('') (p)) (s)

См. также matchAll.

> S.match (/(good)?bye/) ('goodbye')
Just ({"groups": [Just ("good")], "match": "goodbye"})

> S.match (/(good)?bye/) ('bye')
Just ({"groups": [Nothing], "match": "bye"})

matchAll :: GlobalRegExp -> String -> Array { match :: String, groups :: Array (Maybe String) }

Принимает шаблон и строку, и возвращает массив записей совпадений.

groups :: Array (Maybe String) учитывает существование необязательных групп захвата.

См. также match.

> S.matchAll (/@([a-z]+)/g) ('Hello, world!')
[]

> S.matchAll (/@([a-z]+)/g) ('Hello, @foo! Hello, @bar! Hello, @baz!')
[{"groups": [Just ("foo")], "match": "@foo"}, {"groups": [Just ("bar")], "match": "@bar"}, {"groups": [Just ("baz")], "match": "@baz"}]

Строка

toUpper :: String -> String

Возвращает заглавные буквы своего аргумента.

См. также toLower.

> S.toUpper ('ABC def 123')
"ABC DEF 123"

toLower :: String -> String

Возвращает строчные буквы своего аргумента.

См. также toUpper.

> S.toLower ('ABC def 123')
"abc def 123"

trim :: String -> String

Удаляет начальные и конечные пробельные символы.

> S.trim ('\t\t foo bar \n')
"foo bar"

stripPrefix :: String -> String -> Maybe String

Возвращает Just часть заданной строки (второй аргумент) после удаления заданного префикса (первый аргумент), если строка начинается с префикса; в противном случае возвращает Nothing.

См. также stripSuffix.

> S.stripPrefix ('https://') ('https://sanctuary.js.org')
Just ("sanctuary.js.org")

> S.stripPrefix ('https://') ('http://sanctuary.js.org')
Nothing

stripSuffix :: String -> String -> Maybe String

Возвращает Just часть заданной строки (второй аргумент) после удаления заданного суффикса (первый аргумент), если строка заканчивается на суффикс; в противном случае возвращает Nothing.

См. также stripPrefix.

> S.stripSuffix ('.md') ('README.md')
Just ("README")

> S.stripSuffix ('.md') ('README')
Nothing

words :: String -> Array String

Принимает строку и возвращает массив слов, которые содержит строка (слова разделены пробельными символами).

См. также unwords.

> S.words (' foo bar baz ')
["foo", "bar", "baz"]

unwords :: Array String -> String

Принимает массив слов и возвращает результат объединения слов с разделяющими пробелами.

См. также words.

> S.unwords (['foo', 'bar', 'baz'])
"foo bar baz"

lines :: String -> Array String

Принимает строку и возвращает массив строк, содержащихся в строке (строки разделены символами новой строки: '\n' или '\r\n' или '\r'). Результирующие строки не содержат символов новой строки.

См. также unlines.

> S.lines ('foo\nbar\nbaz\n')
["foo", "bar", "baz"]

unlines :: Array String -> String

Принимает массив строк и возвращает результат объединения строк после добавления заключительного символа новой строки ('\n') к каждой.

См. также lines.

> S.unlines (['foo', 'bar', 'baz'])
"foo\nbar\nbaz\n"

splitOn :: String -> String -> Array String

Возвращает подстроки своего второго аргумента, разделённые вхождениями своего первого аргумента.

См. также joinWith и splitOnRegex.

> S.splitOn ('::') ('foo::bar::baz')
["foo", "bar", "baz"]

splitOnRegex :: GlobalRegExp -> String -> Array String

Принимает шаблон и строку, и возвращает результат разделения строки на каждой неперекрывающейся позиции шаблона.

Свойства:

  • forall s :: String, t :: String. S.joinWith (s) (S.splitOnRegex (S.regex ('g') (S.regexEscape (s))) (t)) = t

См. также splitOn.

> S.splitOnRegex (/[,;][ ]*/g) ('foo, bar, baz')
["foo", "bar", "baz"]

> S.splitOnRegex (/[,;][ ]*/g) ('foo;bar;baz')
["foo", "bar", "baz"]

© 2020 Sanctuary
© 2016 Plaid Technologies, Inc.
Licensed under the MIT License.
https://sanctuary.js.org/

Spec-Zone.ru

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