(SML) — компилируемый язык программирования общего назначения , основанный на системе типов Хиндли — Милнера.

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

SML был первым самостоятельным компилируемым языком в семействе ML и до сих пор служит опорным языком в сообществе по развитию ML (). В SML впервые была реализована уникальная аппликативная система модулей — язык модулей ML.

Общие сведения Язык изначально ориентирован на программных систем: он предоставляет эффективные средства абстракции и модульности, обеспечивая высокий коэффициент повторного использования кода, и это делает его подходящим также для быстрого прототипирования программ, в том числе и . Например, в процессе разработки (тогда ещё экспериментального) компилятора ( на SML), порой приходилось вносить радикальные изменения в реализации ключевых структур данных, влияющих на десятки модулей — и новая версия компилятора была готова в течение дня. (см. также ICFP Programming Contest за 2008, 2009.) При этом, в отличие многих других языков, подходящих для быстрого прототипирования, SML может очень эффективно компилироваться.

SML известен своим относительно низким порогом вхождения и служит языком обучения программированию во многих университетах мира. Обширно документирован в рабочем виде, активно используется учёными в качестве базы для исследования новых элементов языков программирования и идиом (см., например, полиморфизм структурных типов). К настоящему времени все реализации языка (включая устаревшие) стали открытыми и свободными.

Отличительные особенности Язык имеет математически точное () формальное определение, называемое «Определением» (). Для Определения построено доказательство полной типобезопасности, что гарантирует устойчивость программ и предсказуемое поведение даже при некорректных входных данных и возможных ошибках программистов. Даже содержащая ошибку программа на SML всегда продолжает вести себя как ML-программа: она может навечно уйти в расчёты или породить исключение, но она не может обрушиться.

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

SML реализует выдающиеся средства поддержки за счёт наиболее мощной и выразительной системы модулей среди известных (язык модулей ML). В SML реализована ранняя версия языка модулей, являющаяся отдельным слоем языка: модули могут содержать объекты ядра языка, но не наоборот.

В отличие многих других языков семейства ML (OCaml, Haskell, F#, Felix, Opa, Nemerle и других), SML весьма минималистичен: он не имеет изначально встроенных средств объектно-ориентированного программирования, средств конкурентности, ad-hoc-полиморфизма, динамической типизации, генераторов списков и многих других возможностей. Однако, SML отличается ортогональностью (то есть реализует минимально необходимый, но полный набор максимально различных элементов), что позволяет сравнительно легко эмулировать прочие возможности, и необходимые для этого приёмы широко освещены в литературе. Фактически, SML позволяет использовать сколь угодно высокоуровневую функциональность в качестве примитивной для реализации функциональности ещё более высокого уровня. В частности, построены модели реализации классов типов и монад с использованием только стандартных конструкций SML, а также средств объектно-ориентированного программирования. Более того, SML является одним из немногих языков, в котором непосредственно реализованы продолжения первого класса.

Возможности Мощная выразительная система типов является отличительной особенностью ML и его потомков. Она обеспечивает надёжность программ за счёт раннего выявления ошибок, высокий коэффициент повторного использования кода, высокий потенциал к оптимизации, сочетая эти качества с немногословностью и выразительностью на уровне динамически типизируемых языков. Наиболее характерными чертами, присущими Х-М, являются полиморфизм типов, а также алгебраические типы данных и сопоставление с образцом на них.

Реализация Х-М в SML имеет следующие особенности: поддерживается полная абстракция и единообразие типов: любой конструктор типов применим к любому типу, и вводимые пользователем типы используются неотличимо от встроенных полиморфизм типов ограничен пренексным полиморфизмом и имеет дополнительные ограничения отдельное место отводится типам, допускающим проверку на равенство () выведение почти всех типов (за единичными исключениями) Разнообразие встроенных разновидностей типов-произведений, используемых без необходимости предварительного объявления: записи кортежи (реализованные в действительности как записи с номерами в качестве имён полей) массивы (служащие для обеспечения высокой эффективности — см. далее) исключения имеют особую семантику: тип исключения является единственным в языке расширяемым типом (), то есть всякое определение exception X вводит в программу новую конструирующую функцию X для типа exn. Как следствие, определения исключений являются порождающими, то есть повторение идентичного определения exception Foo exception Foo вводит два разных конструктора, несовместимых друг с другом, и из-за совпадения имён второй заслоняет видимость первого. Это делает механизм динамической обработки исключений статически типобезопасным (но не гарантирует отсутствие необработанных исключений — соответствующие доработки системы типов были предложены много позже — см. полиморфизм управляющих конструкций).

Поддержка функционального программирования «всё — выражение» () все функции являются объектами первого класса (представленными в виде замыканий) доступно каррирование для функций (но не для конструкторов типов) по умолчанию все объявляемые значения константны лексическая область видимости (позволяющее инкапсулировать изменяемое состояние в функции) лямбда-абстракция гарантия оптимизации хвостовых вызовов (это особенно важно для эффективной реализации продолжений — см. программирование в стиле передачи продолжений)

Поддержка императивного программирования последовательное исполнение выражений в однозначном порядке (слева направо) мутабельные ячейки, аккуратно обособленные в системе типов в виде ссылок, обеспечивающих полную безопасность по типам и по доступу к памяти (и за их счёт возможность эмуляции вызова по ссылке) мутабельные массивы (отдельно от константных, которые также доступны) обработка исключений цикл while полное сохранение «духа ML» в императивных участках кода и возможность их безопасного смешивания с чистыми.

Обеспечение высокой эффективности программ энергичная семантика передачи параметров мутабельные ячейки стандартная поддержка нескольких разновидностей массивов: константных (Vector) и мутабельных (Array), в том числе двухмерных (Array2), мономорфных (MonoVector, MonoArray) и полиморфных; а также их некопирующих срезов. Строковые типы, как и в Си, реализованы посредством массивов символов (то есть тип string определён как char vector), и также доступны их некопирующие срезы (тип substring). гарантия оптимизации хвостовых вызовов полное статическое разрешение типов всех выражений, включая полиморфную проверку значений на равенство, с полным удалением информации о типах в целевом коде (но остаётся контроль переполнения) (в некоторых реализациях) очень тонкий и быстрый FFI, доступность каламбуров типизации, ручной контроль над сборщиком мусора и другие нестандартные особенности

Способы использования В отличие от многих языков, SML предоставляет большое многообразие способов своего использования: интерактивное доказательство теорем REPL и явная загрузка модулей (традиционная для потомков Лиспа) пакетная компиляция (традиционная для потомков Алгола и BCPL) полнопрограммно-оптимизирующая компиляция (порой позволяющая конкурировать в быстродействии с Си — см. MLton) интерпретация (очень редко)

При этом в определённых режимах возможны самые разные целевые платформы и стратегии компиляции: в машинный код (на данный момент покрывается порядка десятка семейств архитектур; теоретически кроссплатформенность может быть существенно шире, чем у всех потомков Алгола и BCPL, за счёт более высокого уровня абстракции от машинного языка, и в каждом случае потенциально возможно создание эффективно оптимизирующего компилятора) в общепринятые байт-коды (JVM, .Net) в собственные байт-коды в языки программирования общего назначения семантически более низкого уровня (Си, Ada, Java, Ассемблер — только пакетно или полнопрограммно) в другие диалекты ML (см. Isabelle (система автоматического доказательства теорем) и )

Сами стратегии компиляции также существенно различаются: , в стиле передачи продолжений, представление адресов функций глобальным вариантным типом. сохранение явных потоков исходного кода, автоматическое распараллеливание, уплощение многопоточного исходного кода до линейного. обёрнутое (boxed) или не-обёрнутое (unboxed) представление примитивных типов динамическая или статическая сборка мусора, в одном потоке с приложением или в отдельном, полностью автоматическая или с возможностью явного контроля.

Язык

Базовая семантика

Объявления, выражения, блоки, функции

Примитивные типы

Составные и определяемые типы

Мутабельные значения

Ограничение на значения Ограничение на значения ()

Управляющие конструкции

Крупномасштабное программирование

Модульность

Система модулей SML является наиболее развитой системой модулей в языках программирования. Она повторяет семантику (), так что зависимости между крупными компонентами программ строятся подобно зависимостям мелкого уровня. Эта система модулей состоит из трёх видов модулей: структур (structure) сигнатур (signature) функторов (functor)

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

Функторы представляют собой «функции над структурами», позволяя разрывать зависимости времени компиляции и описывать параметризованные модули. Они дают возможность типобезопасным образом описывать вычисления над компонентами программ, которые в других языках могут реализовываться только посредством метапрограммирования — как шаблоны C++, только без боли и страданий, или макроязык Лиспа, только со статическим контролем безопасности порождаемого кода. Большинство языков вовсе не имеют ничего, сравнимого с функторами.

Принципиальным отличием языка модулей ML является то, что результат функтора может включать не только значения, но и типы, причём они могут зависеть от типов, входящих в состав параметра функтора. Этим модули ML оказываются наиболее близки в своей выразительности к системам с зависимыми типами, но, в отличие от последних, модули ML могут быть редуцированы в плоскую (см. Язык модулей ML#F-преобразование Россберга — Руссо — Дрейера).

Синтаксис и синтаксический сахар Синтаксис языка очень краток, по количеству зарезервированных слов занимает промежуточную позицию между Haskell и Pascal.

SML имеет контекстно-свободную грамматику, хотя в ней отмечены некоторые неоднозначности. использует LALR(1), но в одном месте присутствует LALR(2).

Список ключевых слов языка (совпадающие с ними идентификаторы не допускаются): abstype and andalso as case datatype do else end eqtype exception fn fun functor handle if in include infix infixr let local