SML был первым самостоятельным компилируемым языком в семействе ML и до сих пор служит опорным языком в сообществе по развитию ML (successor ML)[11]. В SML впервые была реализована уникальная аппликативная система модулей — язык модулей ML.
SML известен своим относительно низким порогом вхождения и служит языком обучения программированию во многих университетах мира[12]. Обширно документирован в рабочем виде, активно используется учёными в качестве базы для исследования новых элементов языков программирования и идиом (см., например, полиморфизм структурных типов). К настоящему времени все реализации языка (включая устаревшие) стали открытыми и свободными.
Отличительные особенности
Язык имеет математически точное (англ.rigorous) формальное определение, называемое «Определением»➤ (англ.The Definition). Для Определения построено доказательство полной типобезопасности, что гарантирует устойчивость программ и предсказуемое поведение даже при некорректных входных данных и возможных ошибках программистов. Даже содержащая ошибку программа на SML всегда продолжает вести себя как ML-программа: она может навечно уйти в расчёты или породить исключение, но она не может обрушиться[13].
SML реализует выдающиеся средства поддержки крупномасштабного программирования[англ.] за счёт наиболее мощной и выразительной системы модулей среди известных (язык модулей ML). В SML реализована ранняя версия языка модулей, являющаяся отдельным слоем языка: модули могут содержать объекты ядра языка, но не наоборот[14].
В отличие многих других языков семейства ML (OCaml, Haskell, F#, Felix, Opa, Nemerle и других), SML весьма минималистичен: он не имеет изначально встроенных средств объектно-ориентированного программирования, средств конкурентности, ad-hoc-полиморфизма, динамической типизации, генераторов списков и многих других возможностей. Однако, SML отличается ортогональностью[15] (то есть реализует минимально необходимый, но полный набор максимально различных элементов), что позволяет сравнительно легко эмулировать прочие возможности, и необходимые для этого приёмы широко освещены в литературе➤. Фактически, SML позволяет использовать сколь угодно высокоуровневую функциональность в качестве примитивной для реализации функциональности ещё более высокого уровня[16]. В частности, построены модели реализации классов типов и монад с использованием только стандартных конструкций SML, а также средств объектно-ориентированного программирования[17]. Более того, SML является одним из немногих языков, в котором непосредственно реализованы продолжения первого класса.
поддерживается полная абстракция и единообразие типов: любой конструктор типов применим к любому типу, и вводимые пользователем типы используются неотличимо от встроенных[18]
кортежи (реализованные в действительности как записи с номерами в качестве имён полей)
массивы (служащие для обеспечения высокой эффективности — см. далее)
исключения имеют особую семантику: тип исключения является единственным в языке расширяемым типом (extensible type), то есть всякое определение exception X вводит в программу новую конструирующую функциюX для типа exn. Как следствие, определения исключений являются порождающими, то есть повторение идентичного определения exception Foo exception Foo вводит два разных конструктора, несовместимых друг с другом, и из-за совпадения имён второй заслоняет видимость первого. Это делает механизм динамической обработки исключений статически типобезопасным (но не гарантирует отсутствие необработанных исключений — соответствующие доработки системы типов были предложены много позже — см. полиморфизм управляющих конструкций).
Поддержка функционального программирования
«всё — выражение» (англ.everything is an expression)
стандартная поддержка нескольких разновидностей массивов: константных (Vector) и мутабельных (Array), в том числе двухмерных (Array2), мономорфных (MonoVector, MonoArray) и полиморфных; а также их некопирующих срезов. Строковые типы, как и в Си, реализованы посредством массивов символов (то есть тип string определён как char vector), и также доступны их некопирующие срезы (тип substring).
полное статическое разрешение типов всех выражений, включая полиморфную проверку значений на равенство, с полным удалением информации о типах в целевом коде (но остаётся контроль переполнения)
(в некоторых реализациях) очень тонкий и быстрый FFI➤, доступность каламбуров типизации, ручной контроль над сборщиком мусора и другие нестандартные особенности
Способы использования
В отличие от многих языков, SML предоставляет большое многообразие способов своего использования[21]:
При этом в определённых режимах возможны самые разные целевые платформы и стратегии компиляции➤:
в машинный код (на данный момент покрывается порядка десятка семейств архитектур; теоретически кроссплатформенность может быть существенно шире, чем у всех потомков Алгола и BCPL, за счёт более высокого уровня абстракции от машинного языка[22], и в каждом случае потенциально возможно создание эффективно оптимизирующего компилятора)
Система модулей SML является наиболее развитой системой модулей в языках программирования. Она повторяет семантику ядра ML (англ.Core ML), так что зависимости между крупными компонентами программ строятся подобно зависимостям мелкого уровня. Эта система модулей состоит из трёх видов модулей:
структур (structure)
сигнатур (signature)
функторов (functor)
Структуры похожи на модули в большинстве языков программирования. Сигнатуры служат интерфейсами структур, но не привязываются жёстко к определённым структурам, а выстраивают отношения по схеме «многие-ко-многим», позволяя гибко управлять видимостью компонентов структур в зависимости от нужд контекста программы.
Функторы представляют собой «функции над структурами», позволяя разрывать зависимости времени компиляции и описывать параметризованные модули. Они дают возможность типобезопасным образом описывать вычисления над компонентами программ, которые в других языках могут реализовываться только посредством метапрограммирования[23] — как шаблоны C++, только без боли и страданий[24], или макроязык Лиспа, только со статическим контролем безопасности порождаемого кода[23]. Большинство языков вовсе не имеют ничего, сравнимого с функторами[25].
Принципиальным отличием языка модулей ML является то, что результат функтора может включать не только значения, но и типы, причём они могут зависеть от типов, входящих в состав параметра функтора. Этим модули ML оказываются наиболее близки в своей выразительности к системам с зависимыми типами, но, в отличие от последних, модули ML могут быть редуцированы в плоскую Систему Fω[англ.] (см. Язык модулей ML#F-преобразование Россберга — Руссо — Дрейера).
Синтаксис и синтаксический сахар
Синтаксис языка очень краток, по количеству зарезервированных слов занимает промежуточную позицию между Haskell и Pascal[26].
Разумеется, использование таких имён на практике не желательно, но если предыдущий автор поддерживаемого кода их интенсивно применял, то благодаря формальному определению, становится возможным (и SML сам позволяет довольно легко эту задачу решить) написание препроцессора для исправления мнемоники.
Исключаются лишь следующие цепочки символов:
: | = => -> # :>
Причина этого ограничения заключена в их особой роли в синтаксисе языка:
В SML не предусмотрено встроенного синтаксиса для массивов и векторов (константных массивов). Некоторые реализации в той или иной мере поддерживают синтаксис для массивов ([|1,2,3|]) и векторов (#[1,2,3]) в качестве расширения.
Стандартная библиотека SML носит название Базиса (англ.Basis). Она формировалась много лет, пройдя тщательное тестирование на реальных задачах на базе SML/NJ[англ.]➤, её черновик был опубликован в 1996 году[28], и затем её спецификация была официально издана в 2004 году[29]. В этот период уже появлялись руководства по её использованию[30]. Базисная библиотека реализует лишь необходимый минимум модулей: тривиальные типы данных, арифметика над ними, ввод-вывод, платформенно-независимый интерфейс к операционной системе, и т. п., но не реализует более сложную функциональность (например, многопоточность). Многие компиляторы дополнительно представляют различные экспериментальные библиотеки.
Компиляторы могут использовать знания о Базисе для применения заранее оптимизированных алгоритмов и специализированных техник оптимизации: например, MLton➤ использует нативное представление типов Базиса (в точности соответствующее примитивным типам языка Си), а также простейших агрегатных типов, составленных из них.
Как и в большинстве языков, в Базисе SML действует ряд определённых архитектурных и синтаксических соглашений. Прежде всего это тривиальные составляющие стандартных структур, таких как сходные по названию и сигнатурам комбинаторы (такие как fold). Далее, это распространяющаяся на большинство типов схема преобразования в строковый тип и обратно➤.
Конверторы и сканеры
Стандартная схема преобразования в строковый тип и обратно инкапсулирована в структуру StringCvt:
Схема преобразования не ограничивается перечислением обоснований систем счисления, как в Си (BIN, OCT, DEC, HEX). Она распространяется на программирование высшего порядка[англ.], позволяя описывать операции чтения значений конкретных типов из абстрактных потоков и записи в них, и затем преобразовывать простые операции в более сложные посредством комбинаторов. В роли потоков могут выступать как стандартные потоки ввод-вывода, так и просто агрегатные типы, такие как списки или строки.[31]
Ключевым ингредиентом этой схемы являются ридеры, то есть значения типа ('a,'b) reader. Интуитивно, ридер — это функция, которая принимает на вход поток типа 'b и предпринимает попытку считать из него значение типа 'a, возвращая либо считанное значение и «остаток» потока, либо NONE в случае неудачи. Важной разновидностью ридеров являются сканеры, или сканирующие функции. Для данного типа T сканирующая функция имеет тип
(char,'b)reader->(T,'b)reader
— то есть представляет собой конвертор из ридера символов в ридер данного типа. Сканеры входят в состав многих стандартных модулей, например, сигнатура INTEGER включает сканер для целых чисел:
Числа считываются атомарным образом, но ридеры могут считывать из потоков и цепочки поэлементно, например, посимвольно строку из строки:
funstringGetc(s)=letvalss=Substring.full(s)incaseSubstring.getc(ss)ofNONE=>NONE|SOME(c,ss')=>SOME(c,Substring.string(ss'))end;stringGetc("hello");(* val it = SOME (#"h","ello") : (char * string) option *)stringGetc(#2(valOfit));(* val it = SOME (#"e","llo") : (char * string) option *)stringGetc(#2(valOfit));(* val it = SOME (#"l","lo") : (char * string) option *)stringGetc(#2(valOfit));(* val it = SOME (#"l","o") : (char * string) option *)stringGetc(#2(valOfit));(* val it = SOME (#"o","") : (char * string) option *)stringGetc(#2(valOfit));(* val it = NONE : (char * string) option *)
Сканеры позволяют создавать ридеры из имеющихся ридеров, например:
valstringGetInt=Int.scanStringCvt.DECstringGetc
Структура StringCvt предоставляет также ряд вспомогательных функций. Например, splitl, takel и dropl комбинируют символьные ридеры с символьными предикатами, позволяя фильтровать потоки.
Следует отметить, что не символьные ридеры являются особым случаем ридеров вообще, а наоборот[32]. Причина этого в том, что извлечение подпоследовательности из последовательности представляет собой обобщение извлечения подстроки из строки.
Портирование
Большинство реализаций языка достаточно строго соответствуют Определению➤. Различия заключаются в технических деталях, таких как бинарный формат раздельно компилируемых модулей, реализация FFI➤ и др. На практике, реальная программа должна отталкиваться от некоего базиса (минимального набора типов, средств ввода-вывода и т. д.). Однако, Определение предъявляет лишь минимальные требования к составу начального базиса, так что единственный обозримый результат корректной программы согласно Определению состоит в том, что программа завершается либо порождает исключение, и большинство реализаций совместимы на этом уровне[33].
Однако, даже в стандартном Базисе➤ заложены определённые потенциальные проблемы портируемости. Например[33], константа Int.maxInt содержит значение наибольшего возможного целого, упакованное в опциональный тип[англ.], и его необходимо извлекать либо сопоставлением с образцом, либо вызовом функции valOf. Для типов конечной размерности значение IntN.maxInt равно SOME(m), и использование обоих способов извлечения равнозначно. Но IntInf.maxInt равно NONE, так что прямое обращение к содержимому через valOf породит исключениеOption. По умолчанию IntInf открыта, например, в компиляторе Poly/ML➤.
С определёнными усилиями возможна разработка программ, свободно портируемых между всеми актуальными реализациями языка. Примером такой программы является HaMLet➤.
Инструментарий разработки
К настоящему времени Standard ML полностью стал достоянием общественности: все реализации являются бесплатными и открытыми и распространяются под самыми лояльными лицензиями (BSD-style, MIT); тексты Определения языка➤ (как в версии 1990 года, так и в ревизированной версии 1997 года) и спецификации Базиса➤ также доступны бесплатно➤.
SML имеет большое число реализаций. Значительная их часть написана на самом SML; исключение составляют рантаймы некоторых компиляторов, написанные на Си и Ассемблере, а также система Poplog[англ.]➤.
MLton (произносится «ми́лтон») (основная статья) (сайт проекта) — кроссплатформенный полнопрограммно-оптимизирующий компилятор. Обеспечивает для программ на SML быстродействие на уровне Си/C++ за счёт агрессивных оптимизаций, в том числе раскрытия рамок модулей, полной мономорфизации и дефункциализации[англ.] программы и нативного (необёрнутого и бестегового) представления примитивных типов, строк и массивов; имеет прямой FFI➤; для длинной арифметики использует GnuMP. Порождает нативный код для большого числа архитектур под Unix-like ОС (под Windows требует Cygwin либо MinGW); имеет бэк-энды в Си, C--, LLVM. Включает полную Базисную библиотеку (даже все опциональные структуры), имеет свои порты множества характерных библиотек SML/NJ[англ.]➤, в том числе реализацию продолжений и CML➤. FFI➤ обеспечивает вызовы в обоих направлениях (функций Си из кода на SML и наоборот), вплоть до взаимной рекурсии. Сопровождается очень богатой документацией, включая описание трюков с нетривиальным использованием языка, позволяющих расширять его полезными идиомами➤. Недостатками, вследствие глобального анализа и множества этапов преобразований, являются значительные затраты времени и памяти для работы.
Poly/ML[38] — кроссплатформенный оптимизирующий компилятор. Порождает достаточно быстрый код, поддерживает многопроцессорные системы (на потоках POSIX), осуществляет параллельную сборку мусора, обеспечивая соиспользование неизменяемых структур данных; по умолчанию использует длинную арифметику (с сигнатурой INTEGER на верхнем уровне связана структура IntInf). Предоставляет прямой интерфейс к WinAPI и X Window System. Бинарная реализация поставляется под Windows; под остальными ОС необходимо собирать исходные коды самостоятельно. Порождает нативный код для i386, PowerPC, SPARC, имеет бэк-энд в байт-код для работы на неподдерживаемых платформах. Poly/ML лежит в основе Isabelle (системы автоматического доказательства теорем), вместе с SML/NJ[англ.]➤.
SML# (не путать с SML.NET➤) — оптимизирующий компилятор SML с расширениями (формирующими диалект SML#➤). Название не должно вводить в заблуждение, SML# компилирует в нативный код и не имеет отношения к платформе .NET (SML# появился на несколько лет раньше). Порождает нативный код для x86 под POSIX. Начиная с версии 2.0, бэк-энд основан на LLVM, что позволит в дальнейшем расширить список поддерживаемых архитектур. В версии 3.0 была реализована поддержка x86-64 и полностью конкурентный сборщик мусора, обеспечивающий эффективное использование многоядерных систем и отсутствие пауз в работе программы. Обеспечивает неплохое быстродействие, в том числе за счёт нативного (необёрнутого и бестегового) представления примитивных типов и прямого FFI➤ к Си и SQL; в ближайшем будущем планируются более сильные оптимизации. Включает также генератор красивой печати[англ.], генератор документации.
TILT, или TIL-Two (исходные коды (Git)) — компилятор, основанный на идее использования в процессе компиляции исключительно типобезопасных промежуточных языков (Typed Intermediate Language, TIL — отсюда название), вплоть до типизированного ассемблера[англ.], с целью сохранения безопасности программы на всех этапах преобразований и оптимизации. Фронт-энд компилятора основан на семантике Харпера — Стоуна➤[42]. Разработан Робертом Харпером[англ.] с коллегами в исследовательских целях в середине 1990-х годов и с тех пор не поддерживается.
FLINT (страница проекта на Yale.edu) аналогичен TILT➤, но внутренний язык не имеет выделенного исчисления модулей, при этом внешний язык поддерживает модули высшего порядка. FLINT был внедрён в состав SML/NJ, что повысило быстродействие последнего.[43]
Alice — кроссплатформенный компилятор SML с расширениями (формирующими диалект Alice➤) в байт-код виртуальной машины с поддержкой JIT. Ориентирован на разработку распределённых систем. Имеет собственную REPL-IDE со встроенным инспектором, которая позволяет компилировать выделяемые фрагменты кода (при условии их самодостаточности) и затем обеспечивает интерактивную информацию о выведенных типах. Поддерживается раздельная компиляция. Работает под Windows и различными Unix-like системами. В дополнение к стандартному Базису предоставляет ряд дополнительных библиотек, имеет интерфейс к SQLite и Gtk+. Сопровождается детальными руководствами по использованию предоставляемых языковых и библиотечных расширений (предполагающими знание SML).
Moscow ML[44] — легковесный компилятор в байт-код. Основан на среде выполнения Caml Light, поддерживает REPL и пакетную компиляцию. Компилирует быстро, но оптимизация незначительна[45]. Предоставляет расширения языка (функторы высшего порядка, пакеты, квазицитирование[англ.]), имеет интерфейс➤ к ряду системных и мультимедийных библиотек. Разработан в России в институте Келдыша под руководством Романенко А. С. для учебных целей; поддержку языка модулей с расширениями реализовал Клаудио Руссо (автор семантики пакетов).
SML.NET[46] — не путать с SML#➤ — полнопрограммно-оптимизирующий компилятор для платформы .Net. Вырос из компилятора MLj для платформы JVM. Предоставляет интерфейс для связывания с другими .NET-языками. Имеет собственную систему анализа зависимостей между модулями. Компилирует только модули целиком, раскрывая их рамки. Управляется как из обычной командной строки, так из собственного режима REPL.
SMLtoJs[47] — компилятор в исходный код на JavaScript. Осуществляет множественные оптимизации, в том числе раскрывает рамки модулей. Для работы использует MLton➤ и ML Kit➤.
sml2c[49] — компилятор в исходный код на Си. Сделан на основе внешнего интерфейса и среды выполнения SML/NJ[англ.]➤ и поддерживает многие из его расширений (в том числе первоклассные продолжения). Порождает код на портируемом ANSI C, но из-за различий в свойствах семантики даёт 70-100% замедление по сравнению с прямой трансляцией SML в машинный код[5]. Работает только с определениями уровня модулей в пакетном режиме. Программы уровня модулей, компилируемые SML/NJ, могут компилироваться SML2c без изменений. В отличие от SML/NJ, не поддерживает отладку и профилирование на уровне исходного кода.
HaMLet[52] — эталонная реализация SML. Представляет собой интерпретатор непосредственного, строка-к-строке, воплощения Определения➤ языка. Не предназначен для промышленного применения — крайне неэффективен и предоставляет малоинформативные сообщения об ошибках — вместо этого он служит платформой для исследований самого языка и поиска возможных недостатков Определения. HaMLet сам полностью написан на SML (25 тыс.строк кода) без использования Си, и способность некоторого компилятора SML собрать коды HaMLet можно рассматривать как признак достаточно хорошей реализации Определения языка и Базисной библиотеки. В частности, коды HaMLet способны скомпилировать SML/NJ[англ.]➤, MLton➤, Moscow ML➤, Poly/ML➤, Alice➤, ML Kit➤, SML#➤, и, разумеется, он сам. HaMLet также имеет режим «HaMLet S», являющийся референсной реализацией текущей версии successor ML (sML). Разработан и поддерживается Андреасом Россбергом.
Edinburgh LCF (Logic for Computable Functions) (основная статья[англ.]) (исходные коды доступны в составе Isabelle) — интерактивной системы доказательства теорем, исторически первая реализация корневого языка ML (до введения языка модулей и формирования SML).
Неактуальные реализации
Poplog[англ.][54] — инкрементальный компилятор и интегрированная среда разработки, ориентированная на работу в сфере искусственного интеллекта. Предоставляет возможность смешивания одновременно нескольких языков, в число которых входит POP-11[англ.], Prolog, Common Lisp и SML. Внутреннее представление всех языков основано на POP-11[англ.] — Лиспо-подобном рефлективном языке; на нём же реализован сам Poplog. Включает в себя редактор, похожий на Emacs, и поддерживает GUI, но только под X Window System; под Windows предоставляет лишь консоль. Название Poplog представляет собой акроним из «POP-11» и «Prolog». Несмотря на то, что Poplog активно развивается, он отстал от развития языка SML: в настоящее время его реализация SML не соответствует актуальному Определению (SML'97) и не реализует Базисную библиотеку.
MLWorks[55] — компилятор с полнофункциональной IDE и сопутствующим инструментарием. Ранее был коммерческим, разрабатывался компанией Harlequin[англ.] в 1990-е годы. На рубеже веков владелец сменился и поддержка была прекращена. В 2013 году обрёл нового владельца, который открыл исходные коды и организовал работу по реанимации проекта. По состоянию на 2016 год не работоспособен.
SML#[56] консервативно расширяет SML полиморфизмом записей в модели Ацуси Охори, который в SML# используется для бесшовного встраивания SQL в код на SML для интенсивного database-программирования.
Символ решётки (#) в названии языка символизирует селектор (операцию выбора поля из записи). Одноимённый компилятор➤ претендует на хорошее быстродействие. Разработан и развивается в институте Тохоку (Япония) под руководством самого Охори.
Mythryl[57] — синтаксический вариант SML, нацеленный на повышение скорости разработки под POSIX. Новый синтаксис во многом заимствован из Си; терминология также пересмотрена под более традиционную (например, функторы переименованы в дженерики). При этом авторы подчёркивают, что не намерены создать «очередную свалку языковых возможностей», а придерживаются минималистичной природы SML и опираются на его Определение➤. Реализация является форкомSML/NJ[англ.]➤.
Compilation Manager (CM) и MLBasis System (MLB) — расширения компиляторов для лучшей поддержки модульности (контроля зависимостей). В принципе, для этой цели мог бы использоваться и традиционный для большинства языков make, но язык модулей SML значительно мощнее средств модульности других языков, а make его преимуществ не поддерживает, и не пригоден для работы в режиме REPL[59]. CM изначально реализован в SML/NJ[англ.], затем портирован на MLton. Позже в составе MLton была предложена система MLB и конвертор файлов формата .cm в формат .mlb. Поддержка MLB была добавлена в ML Kit.
Интерфейс внешних функций. В разных компиляторах имеет разную реализацию, что тесно связано с представлением данных (прежде всего, обёрнутое или необёрнутое, теговое или бестеговое). В SML/NJ FFI основан на динамической кодогенерации, и если функция принимает на вход данные общим объёмом n байт и возвращает m байт, то её вызов имеет сложностьn+m[61]. Некоторые компиляторы (MLton➤, SML#➤) используют необёрнутое и бестеговое представление данных и обеспечивают прямые обращения к функциям и данным Си. В последнем случае вынесение медлительных функций в код на Си может существенно повышать общее быстродействие программы[62].
NLFFI (No-Longer-Foreign Function Interface — рус.интерфейс к отныне-более-не-чужеродным функциям)[63] — альтернативный, более высокоуровневый интерфейс внешних функций. NLFFI автоматически порождает связующий код, позволяя подключать *.h-файлы (заголовочные файлыСи) непосредственно в состав проекта на SML (CM➤ или MLB➤), что снимает необходимость ручного кодирования определений FFI➤. Конструктивно идея NLFFI состоит в моделировании системы типов Си посредством типов ML; реализация основана CKit➤. Поставляется с SML/NJ[англ.] и MLton.
CKit — фронт-энд языка Си, написанный на SML. Осуществляет трансляцию исходных кодов на Си (с учётом препроцессора) в AST, реализуемое посредством структур данных языка SML. Лежит в основе реализации NLFFI➤.
Идеоматика, соглашения
К оформлению программ на SML не предъявляется никаких требований, поскольку грамматика языка полностью контекстно-свободна и не содержит явных неоднозначностей. Тем не менее, в ней отмечаются частные проблемы, например, при передаче оператора умножения op * закрывающую скобку необходимо отделять пробелом ((op * )), так как при сплошном написании многие реализации (не все) принимают пару символов *) за закрытие комментария в коде и выдают ошибку.
Однако, всё же существуют определённые рекомендации, нацеленные на улучшение читабельности, модульности и повторного использования кода, а также раннего обнаружения ошибок и повышения модифицируемости (но не для внесения информации о типах в идентификаторы, как это делается, например, в венгерской нотации)[64]. В частности, в SML рекомендуется правило именования идентификаторов уровня ядра языка, аналогичное тому, что требуется в Haskell: fooBar для значений, foo_bar для конструкторов типов, FooBar для конструирующих функций (некоторые компиляторы даже выдают предупреждение при его нарушении). Это связано с особенностью работы механизма сопоставления с образцом, который в общем случае не способен отличить ввод локальной переменной от использования нуль-арного конструктора типов, так что опечатки могут приводить к (сравнительно легко обнаружимым) ошибкам[65].
Наиболее непривычными и неожиданными могут быть:
предпочтение шага отступа в три символа(не в четыре)
частое применение апострофа в идентификаторах (аналогично принятому в математике): если на основе x требуется построить «новый x», то в большинстве языков пишут «x1», а в SML, как и в математике, зачастую «x'» («икс-штрих»).
синтаксис бинарных логических операций «И» и «ИЛИ»: andalso и orelse, соответственно.[66]
синтаксис инфиксных операций конкатенации строк и списков: ^ и @, соответственно (для векторов и массивов не предусмотрены).
Эта-расширение (англ.eta-expansion) выражения e есть выражение fn z => e z, то есть обёртка исходного выражения в лямбда-функцию, где z не встречается в e. Разумеется, это имеет смысл лишь в случае, если e имеет стрелочный тип, то есть является функцией. Эта-расширение принуждает задержку вычисления e до применения функции и повторное его вычисление при каждом применении. Этот приём применяется в SML для преодоления ограничений выразительности, связанных с семантикой ограничения на значения➤. Термин «эта-расширение» заимствован из эта-преобразования в лямбда исчислении, означающего, напротив, редукцию выражения fn z => e z до e в случае, если z не встречается в e (эта-сжатие).[67][68]
Значения, индексированные типами
Значения, индексированные типами (англ.type-indexed values) — это техника, позволяющая ввести в SML поддержку ad-hoc-полиморфизма (которая в нём изначально отсутствует)[69]. Существует целый ряд её вариантов, в том числе нацеленные на поддержку полноценного объектно-ориентированного программирования[17].
Fold
«Fold»[70] — это техника, позволяющая ввести в SML ряд распространённых идиом, включая функции с переменным числом аргументов, именованные параметры функций, значения параметров по умолчанию, синтаксическую поддержку массивов в коде, функциональное обновление записей и косметическое изображение зависимой типизации для обеспечения типобезопасности функций вроде printf.
Принцип
Необходимо определить три функции — fold, step0 и $ — такие, чтобы было верно следующее равенство:
Простейшая программа на SML может быть записана в одну строку:
print"Hello World!\n"
Однако, учитывая ориентированность языка на крупномасштабное программирование[англ.], минимальной всё же следует считать её обёртку в язык модулей (некоторые компиляторы работают только с программами уровня модулей).
Точкой старта программы, вообще говоря, может быть выбрана любая функция, но на практике имеет смысл соблюдать общепринятые соглашения, поэтому стоит добавить такой код:
Для компилятора SML/NJ[англ.]➤ в структуру Main требуется также дополнительно добавить специфичную строку:
val_=SMLofNJ.exportFn("project1",main);
Для многомодульных программ требуется также создать файл проекта для отслеживания зависимостей в менеджере компилятора (некоторые компиляторы делают это автоматически). Например, для SML/NJ следует создать файл с именем sources.cm следующего содержания:
Group
signature HELLO_WORLD
structure HelloWorld
is
helloworld-sig.sml
helloworld.sml
end
Более универсальным с точки зрения поддержки различными компиляторами (но несколько более ограниченным по возможностям) вариантом может быть создание обычного файла исходного кода на SML с линейным перечислением подключаемых файлов:
use"helloworld-sig.sml";use"helloworld.sml";
Выходной машинный код для минимальной программы также получается относительно крупным (в сравнении с реализаций Hello World на Си), поскольку даже самая маленькая программа на SML обязана включать в себя рантайм-систему языка, бо́льшую часть которой составляет сборщик мусора. Однако, не следует воспринимать размер исходного и машинного кодов на начальном этапе как тяжеловесность SML: их причиной является интенсивная ориентированность языка на разработку крупных и сложных систем. Дальнейшее наращивание программ происходит по существенно более пологой кривой, чем в большинстве других статически типизируемых языков, и оверхед становится едва заметным при разработке серьёзных программ[71].
Этот код преобразует по простейшим правилам плоский текст в HTML, оформляя диалог по ролям[72].
Демонстрация работы
Допустим, есть следующий текстовый файл с именем Henry.txt:
Westmoreland. Of fighting men they have full three score thousand.
Exeter. There's five to one; besides, they all are fresh.
Westmoreland. 0 that we now had here
But one ten thousand of those men in England
That do no work to-day!
King Henry V. What's he that wishes so?
My cousin Westmoreland? No, my fair cousin:
If we are marked to die, we are enough
To do our country loss; and if to live,
The fewer men, the greater share of honour.
Тогда вызов программы следующей строкой:
val_=htmlCvt"Henry.txt"
Создаст файл с именем Henry.txt.html следующего содержания:
<P><EM>Westmoreland</EM>. Of fighting men they have full three score thousand.
<P><EM>Exeter</EM>. There's five to one; besides, they all are fresh.
<P><EM>Westmoreland</EM>. 0 that we now had here
<br>But one ten thousand of those men in England
<br>That do no work to-day!
<P><EM>King Henry V</EM>. What's he that wishes so?
<br>My cousin Westmoreland? No, my fair cousin:
<br>If we are marked to die, we are enough
<br>To do our country loss; and if to live,
<br>The fewer men, the greater share of honour.
Этот файл можно открыть в браузере, увидев следующее:
Westmoreland. Of fighting men they have full three score thousand.
Exeter. There's five to one; besides, they all are fresh.
Westmoreland. 0 that we now had here
But one ten thousand of those men in England
That do no work to-day!
King Henry V. What's he that wishes so?
My cousin Westmoreland? No, my fair cousin:
If we are marked to die, we are enough
To do our country loss; and if to live,
The fewer men, the greater share of honour.
Этот код использует Базисную структуру Key, сопоставимую с сигнатурой ORD_KEY, а также глобальный тип order (над которым, в частности, определена функция Key.compare):
datatypeorder=LESS|EQUAL|GREATER
О языке
Быстродействие
Типичные преимущества функционального программирования (типобезопасность, автоматическое управление памятью, высокий уровень абстракции и др.) проявляются в обеспечении надёжности и вообще работоспособности программ, а в ответственных, особенно крупномасштабных[англ.] задачах быстродействие часто играет второстепенную роль. Упор на эти свойства исторически привёл к тому, что программистам на функциональных языках зачастую оказываются недоступны многие эффективные структуры данных (массивы, строки, битовые цепочки), поэтому функциональные программы обычно заметно менее эффективны, чем эквивалентные программы на Си.[73]
ML изначально предоставляет весьма неплохие средства для тонкого контроля за быстродействием➤, однако, исторически➤ реализации ML были крайне медлительными. Тем не менее, ещё в начале 1990-х Эндрю Аппель[англ.] прочил[74] языку SML скорость исполнения выше скорости языка Си, по крайней мере при интенсивной работе со сложноструктурированными данными (но SML не претендует на то, чтобы быть заменой Си в задачах системного программирования). За следующие несколько лет напряжённая работа над развитием компиляторов привела к тому, что скорость исполнения программ на SML повысилась в 20-40 раз[75].
В конце 1990-х Стивен Уикс задался целью добиться от программ на SML максимально возможной производительности и написал дефункторизатор для SML/NJ[англ.]➤, сразу показавший прирост скорости ещё в 2-3 раза. Дальнейшая работа в этом направлении привела к созданию компилятора MLton➤, который к середине нулевых годов XXI века показывал прирост скорости перед другими компиляторами в среднем на два порядка[45], конкурируя с Си (подробнее см. MLton).
Стратегия автоматического управление памятью на основе вывода регионов позволяет устранять затраты на инициализацию и высвобождение памяти из исполнения программы (то есть реализует сборку мусора на этапе компиляции). Компилятор ML Kit использует эту стратегию, позволяя решать задачи реального времени, хотя он уступает MLton по возможностям оптимизации.
На основе фронт-енда SML/NJ[англ.] был разработан компилятор в исходный код на Си — sml2c➤. Он порождает код хорошего качества, но примечательно, что схема компиляции «сначала в Си, затем в машинный код» до двух раз снижает быстродействие по сравнению с прямой компиляцией SML в машинный код из-за семантических различий между SML и Си[5].
Некоторые компиляторы SML предоставляют возможность профилирования кода с целью определения функций, занимающих наибольшее процессорное время (причём результат всегда неожиданный)[73], после чего можно сосредоточиться на их оптимизации средствами SML, либо вынести их в код на Си через FFI➤.
Официальным «стандартом» языка является изданное в виде книги «Определение» (англ.The Definition). Определение сформулировано в строгих математических понятиях и имеет доказаннуюнадёжность. Непротиворечивость Определения позволяет человеку без запуска конкретного компилятора проверить программу на корректность и вычислить её результат; но, с другой стороны, Определение требует высокой квалификации для понимания и не может служить учебником по языку[74].
Доказуемость надёжности не далась сама по себе — Определение было неоднократно пересмотрено прежде, чем увидело свет. Многие языки опираются на общие теории, но при разработке они почти никогда не проверяются на безопасность совместного использования конкретных языковых элементов, являющихся частными приложениями этих теорий, что неизбежно приводит к несовместимости между реализациями языка. Эти проблемы либо игнорируются, либо начинают преподноситься как естественное явление (англ.«not a bug, but a feature»), но в действительности их причиной является то, что язык не был подвергнут математическому анализу[76].
Подробности
Первоначальное Определение, «The Definition of Standard ML», было издано в 1990 году[2]. Спустя год были изданы «Комментарии к Определению» («Commentary on Standard ML»), объясняющие применённые подходы и нотации[77]. Вместе они составляют спецификацию языка, ныне известного как «SML'90». В течение следующих лет появился ряд критических замечаний и предложений по улучшению (одним из наиболее известных среди которых являются просвечивающие суммы Харпера — Лилибриджа), и в 1997 году многие из них были собраны в ревизированной версии Определения, «The Definition of Standard ML: Revised»[3], определив версию языка «SML'97», сохраняющего обратную совместимость с прежним. Ревизированное Определение использует принципы, описанные в Комментариях 1991 года, так что намеревающимся досконально изучить Определение SML рекомендуется сначала изучать SML'90, и лишь затем SML'97.[78]
Со временем в тексте Определения был обнаружен ряд неоднозначностей и упущений[79][80][81]. Однако, они не умаляют строгости Определения по сути — доказательство его надёжности было механизировано в Twelf[англ.][82]. Большинство реализаций достаточно строго соответствуют Определению, отклоняясь в технических особенностях — бинарных форматах, FFI➤ и пр., а также в особенностях трактовки неоднозначных мест в Определении — всё это приводит к необходимости приложения некоторых дополнительных усилий (существенно меньших, чем для большинства других языков) для обеспечения безупречной портируемости реальных программ на SML между реализациями (небольшие программы в большинстве случаев не имеют проблем портирования).
Определение SML является примером структурной операционной семантики[англ.]!!; оно является не первым формальным определением языка, но первым, однозначно понятным разработчикам компиляторов[83].
Определение оперирует семантическими объектами (semantic objects), описывая их смысл (meaning). Во введении авторы делают акцент на том, что именно семантические объекты (к числу коих, в зависимости от конкретного языка, могут относиться такие понятия как пакет, модуль, структура, исключение, канал, тип, процедура, ссылка, соиспользование и пр.), а не синтаксис, определяют концептуальное представление о языке программирования, и именно на них должно строиться определение всякого языка[84].
Содержание
Согласно Определению, SML разделяется на три языка, надстроенные один над другим: нижний слой, называемый «Ядром языка» (Core language), средний слой, называемый «Модулями» (Modules) и небольшой верхний слой, называемый «Программами» (Programs), представляющий собой совокупность определений верхнего уровня (top-level declarations).
Определение включает около 200 правил вывода (inferrence), записываемых в виде обыкновенной дроби, где в позиции числителя стоит формализованная фраза ML, а в позиции знаменателя — следствие, которое можно заключить, если фраза корректна.
Определение различает три основные фазы в языке[85][86]: разбор (parsing), выработка (elaboration) и вычисление (evaluation). Выработка относится к статической семантике; вычисление — к динамической. Но вычисление здесь не следует путать с исполнением (execution): SML является языком, основанным на выражениях (expression-based language), и получение результата от применения функции ко всем аргументам называется исполнением (execution), а «вычисление функции» означает построение определения её самой. Следует также обратить внимание, что поддержка каррирования в языке означает представление всех функций замыканиями, а это, в свою очередь, означает, что использовать термин «вызов функции» некорректно. Вместо вызова следует говорить о применении функции (function application) — функция просто не может быть вызвана, пока не получит все аргументы; частичное применение функции означает вычисление новой функции (нового замыкания). Для каждого из слоёв языка (Ядро, Модули, Программы) отдельно описывается статическая и динамическая семантика, то есть этапы разбора, выработки и вычисления.
Конкретная реализация языка не обязана проводить все эти различия, они несут лишь формальный характер[86]. Фактически, единственная реализация, которая стремится строго их соблюдать — это HaMLet➤. В частности, выработка без вычисления означает традиционное понятие о компиляции.
Вычисление каждого определения по ходу программы меняет состояние глобального окружения (top-level environment), называемого базисом. Формально, исполнение программы представляет собой вычисление нового базиса как суммы начального базиса и определений программы. Стандартная библиотека в SML представляет собой «базис по умолчанию», доступный всякой программе от её начала, и потому называется просто Базисом. Само Определение содержит только начальный базис (initial basis), содержащий минимально необходимые определения; более обширный Базис был стандартизирован много позже, пройдя длительную отработку на практике➤.
Семантика Харпера — Стоуна
Семантика Харпера — Стоуна (сокращённо «семантика Х-С», англ.HS semantics) представляет собой интерпретацию SML в типизированной системе (typed framework). Семантика SML по Х-С определяется через выработку➤ внешнего языка SML во внутренний язык, представляющий собой явнотипизированное лямбда-исчисление, и, таким образом, служит теоретико-типовым обоснованием языка. Эта интерпретация может рассматриваться как альтернатива Определению➤, формализующая «статические семантические объекты» через выражения типизированного лямбда-исчисления; а также как декларативное описание правил выработки для компиляторов, управляемых типами (англ.type-directed compilers), таких как TILT или SML/NJ➤. Фактически, фронт-енд компилятора TILT воплощает эту семантику, хотя он был разработан на несколько лет раньше.[87][88][89]
Внутренний язык основан на языке XML Харпера — Митчела, но имеет более обширный набор примитивов и более выразительную систему модулей, основанную на просвечивающих суммах Харпера — Лилибриджа. Этот язык пригоден для выработки многих других языков, семантика которых основана на лямбда-исчислении, таких как Haskell и Scheme.
Применение этого подхода заложено в проект successor ML. При этом, изменения в языке, не влияющие на внутренний язык, рассматриваются как кратковременная перспектива (англ.short-term), а требующие его изменения — как долговременная перспектива (англ.long-term).
Разработчики SML изначально установили самую высокую планку требований качества для языка, так что и порог критики располагается намного выше, чем у большинства промышленных языков. Упоминания о недостатках языка SML встречаются в официальной печати так же часто, как и языка C++, и много чаще большинства других языков, но причина вовсе не в негативном отношении к SML — напротив, всякая критика SML производится с очень тёплым отношением к нему. Даже педантичный разбор недостатков SML обычно сопровождается его описанием как «изумительного языка, единственного серьёзного из существующих»[90]. Иначе говоря, исследователи досконально копаются в недостатках, подразумевая, что даже с их учётом SML оказывается более предпочтителен для применения в гигантских наукоёмких проектах, чем многие более популярные языки, и желая довести SML до совершенства.
Основной проблемой для разработчика на SML на сегодняшний день является скудный уровень развития окружения (особенно IDE) и библиотечных наработок.
Безопасность SML означает оверхед на арифметику: из-за требования, что всякая операция должна иметь идентичное поведение на любой платформе, контроль переполнения, деления на ноль и т. п. являются неотъемлемыми компонентами всякой арифметической операции. Это делает язык неэффективным выбором для задач числодробилки, особенно для конвейерных архитектур[91].
OCaml является ближайшим родственником SML, отделившимся от него ещё до стандартизации. OCaml настолько шире развит, что его иногда шутливо называют «SML++». В массовом программировании OCaml существенно опережает SML по популярности; в академических кругах SML значительно чаще является объектом научных изысканий. Ведущий разработчик OCaml Ксавье Леруа является членом совета по successor ML.
OCaml имеет единственную реализацию, включающую два компилятора (в байт-код и в натив), совместимых почти идентично, которая непрерывно эволюционирует, предлагая не только всё лучшее окружение, но и всё более мощные семантические возможности. SML имеет множество реализаций различной направленности, следующих единому Определению языка и Базисной библиотеки, и иногда предлагающих дополнительные возможности.
Haskell является чистым, т.е. не имеет эффектов, и для моделирования изменяемого состояния использует монады, тогда как SML непосредственно поддерживает мутабельные структуры данных➤ (ссылки и массивы) и управляющие эффекты➤ (исключения и циклы).
Haskell местами отклоняется от доказуемой надёжности.
Haskell является ленивым, т.е. основан на вызове по необходимости, и как следствие, использует нестрогое определение функций, что существенно влияет как на выразительные возможности, так и на процесс изучения языка. SML является строгим (энергичным), т.е. основан на вызове по значению, но позволяет легко эмулировать ленивость различной степени и различной эффективности[101].
В Haskell функции (включая функции над типами), как правило, каррированные. В SML многие библиотечные функции определены над кортежами и записями, а конструкторы типов вообще не могут быть каррированными. Это влияет не только на синтаксис, но и на некоторые идиомы и стереотипы. В частности, для функций свёртки в этих языках используется разный порядок следования аргументов, и более того, чаще применяются разные функции свёртки: в SML предпочтительна свёртка налево как допускающая хвостовую оптимизацию, а в Haskell предпочтительна свёртка направо как допускающая работу над псевдобесконечными списками.
Формальная семантика SML ориентирована на интерпретацию, однако большинство его реализаций является компиляторами (в том числе интерактивными компиляторами), некоторые из которых уверенно соперничают по эффективности с языком Си, так как язык хорошо поддаётся глобальному анализу. По той же причине SML может компилироваться в исходный код на других языках высокого или среднего уровня — например, существуют компиляторы из SML в Си и Ada.
Первая версия ML была представлена миру в 1974 году в роли мета-языка для построения интерактивных доказательств в составе системы Edinburgh LCF (Logic for Computable Functions)[англ.]➤[2]. Её реализовали Малькольм Ньюи, Локвуд Моррис и Робин Милнер на платформе DEC10. Первая реализация была крайне неэффективной, так как конструкции ML транслировались в Lisp, который затем интерпретировался[105]. Первое полное описание ML как компонента LCF издано в 1979 году[2].
Около 1980 годаЛука Карделли[англ.] реализовал первый компилятор Vax ML, дополнив ML некоторыми своими идеями. Вскоре Карделли портировал Vax ML на Unix, используя Berkley Pascal. Среда выполнения была переписана на Си, но большая часть компилятора оставалась на Паскале. Работа Карделли вдохновила Милнера на создание SML как самостоятельного языка общего назначения, и они начали совместную работу в Эдинбурге, результатом чего стал компилятор Edinburgh ML➤, выпущенный в 1984 году. В процессе этой работы Майк Гордон придумал ссылочные типы и предложил их Луи Дамасу, который позже защитил на них диссертацию[106]. Одновременно велось сотрудничество Кэмбриджа с INRIA. Жерар Хью из INRIA портировал ML на Maclisp под Multics. INRIA разработали собственный диалект ML, названный Caml, и впоследствии развившийся в OCaml➤. Лоуренс Полсон[англ.] оптимизировал Edinburgh ML➤, так что код на ML стал работать в 4-5 раз быстрее. Вскоре после этого Дэвид Мэтьюз разработал язык Poly на основе ML. Дальнейшая работа в этом направлении привела к созданию среды Poly/ML➤. В 1986 Дэвид МакКуин сформулировал язык модулей ML, и к работе подключился Эндрю Аппель[англ.]. Совместно они начали вести работу над компилятором SML/NJ[англ.], который служил одновременно исследовательской платформой для развития языка и первым промышленным оптимизирующим компилятором. Многие из реализаций языка были первоначально разработаны с использованием SML/NJ[англ.] и затем раскручены.
С опытом крупномасштабных разработок был обнаружен ряд недочётов в Определении языка от 1990 года➤. Часть недостатков была устранена в Ревизии Определения от 1997 года[3], но рамки ревизии исключают потерю обратной совместимости (коды адаптируются косметически, без необходимости переписывания с нуля). В 2004 году была опубликована спецификация на состав Базисной библиотеки (черновик спецификации датируется 1996 годом). Другие недостатки были устранены в других языках: ML породил целое семейство Х-М-типизированных языков. Эти языки завоевали популярность на задаче разработке языков и часто определяются как «DSL для денотационной семантики[англ.]». Исследователи, занимавшиеся развитием и использованием SML на протяжении почти трёх десятилетий, к концу XX века сформировали сообщество по созданию нового языка — successor ML.
Фактически, SML не был первым в семействе после собственно LCF/ML — ему предшествовали такие языки как Cardelli ML и Hope[9]. Французы поддерживают собственный диалект — Caml/OCaml[12]. Тем не менее, говоря «ML», многие подразумевают «SML»[107], и даже пишут через дробь: «ML/SML»[82].
Для первоначального ознакомления с языком может быть полезен краткий (несколько десятков страниц) курс Роберта Харпера[англ.] «Introduction to Standard ML» (доступный в русском переводе[114]), который он использовал для преподавания языка и за следующие два десятилетия расширил до более крупного учебника[115].
Учебным руководством по использованию стандартной библиотеки языка, предполагающим его базовое знание, служит книга Рикардо Пуцеллы[30].
В числе других учебников можно назвать книги Гилмора[116],
Ульмана[117], Шипмана[118], онлайн-книгу Камминга[119].
Среди руководств по профессиональному использованию языка можно выделить книгу Эндрю Аппеля[англ.] (ведущего разработчика SML/NJ[англ.]) «Modern compiler implementation in ML»[120] (у этой книги есть две сестры-близняшки: «Modern compiler implementation in Java» и «Modern compiler implementation in C», эквивалентные по структуре, но использующие другие языки для воплощения излагаемых методов). Имеется также масса статей, издаваемых в таких журналах, как JFP, «ML workshop» и др.[121][122]
Применение
SML, наряду с OCaml, служит первым языком преподавания обучения программированию во многих университетах мира. Среди аппликативных языков они имеют, вероятно, самый низкий собственный порог вхождения.
Lawrence C. Paulson[англ.]. ML for the Working Programmer. — 2nd. — Cambridge, Great Britain: Cambridge University Press, 1996. — 492 с. — ISBN 0-521-57050-6 (твёрдый переплёт), 0-521-56543-X (мягкий переплёт).
Andrew W. Appel. Modern compiler implementation in ML (англ.). — Cambridge, Great Britain: Cambridge University Press, 1998. — 538 p. — ISBN 0-521-58274-1 (hardback), 0-521-60764-7 (paperback).
Anthony L. Shipman. Unix System Programming with Standard ML (англ.). — 2001.
Riccardo Pucella. Notes on Programming Standard ML of New Jersey (англ.). — Last revised January 10, 2001. — Cornell University, 2001.
Bernard Berthomieu.OO Programming Styles in ML. — LAAS Report #2000111, Centre National De La Recherche Scientifique Laboratoire d'Analyse et d'Architecture des Systèmes, 2000.
Riccardo R. Pucella. Reactive Programming in Standard ML (англ.). — Bell Laboratories, Lucent Technologies, 2004.
Milner, Morris, Newey. A Logic for Computable Functions with reflexive and polymorphic types // Arc-et-Senans. — Proc. Conference on Proving and Improving Programs, 1975.
Gordon, Milner, Morris, Newey, Wadsworth. A Metalanguage for Interactive Proof in LCF. — 1977.
Robert Harper[англ.], Christopher A. Stone. A type-theoretic account of Standard ML // Technical Report CMU-CS-96-136R. — Carnegie Mellon University, 1996.
Robert Harper[англ.], Christopher A. Stone. An interpretation of Standard ML in type theory // Technical Report CMU-CS-97-147. — Carnegie Mellon University, 1997.
Human settlement in EnglandJuniper HillJuniper HillLocation within OxfordshireOS grid referenceSP579324Civil parishCottisfordDistrictCherwellShire countyOxfordshireRegionSouth EastCountryEnglandSovereign stateUnited KingdomPost townBrackleyPostcode districtNN13Dialling code01280PoliceThames ValleyFireOxfordshireAmbulanceSouth Central UK ParliamentBanbury List of places UK England Oxfordshire 51°59′17″N 1°09′29″W / 51.988°N 1.158°W...
كهرومغناطيسيةجزء من فيزياء المواضيع كهرباء — قوة كهرومغناطيسية التاريخ timeline of electromagnetism and classical optics (en) تعديل - تعديل مصدري - تعديل ويكي بيانات البرق هو تفريغ كهرباء ساكنة ينتقل بين منطقتين مشحنتين. جزء من سلسلة مقالات حولالكهرومغناطيسية كهرباء مغناطيسية تاريخ علم الكهرباء
Mexican historian and politician In this Spanish name, the first or paternal surname is Alamán and the second or maternal family name is Escalada. Lucas Alamán1860s copy by Alamán's son Pascual of a portrait depicting him in his younger years, currently in the Museo Nacional de Historia.Minister of Interior and Exterior Relations of MexicoIn officeApril 20, 1853 – June 2, 1853PresidentAntonio López de Santa AnnaPreceded byJosé Miguel ArroyoSucceeded byJosé Miguel Arro...
MarquisZeng Jize曾紀澤Menteri untuk RusiaMasa jabatan12 Februari 1880 – 17 Agustus 1886Penguasa monarkiGuangxuPendahuluShao YouyuPenggantiLiu RuifenMenteri untuk Britania RayaMasa jabatan25 Agustus 1878 – 27 Juli 1885Penguasa monarkiGuangxuPendahuluGuo SongtaoPenggantiLiu RuifenMenteri untuk PrancisMasa jabatan25 Agustus 1878 – 28 April 1884Penguasa monarkiGuangxuPendahuluGuo SongtaoPenggantiXu Jingcheng Informasi pribadiLahir(1839-12-07)7 Desember 1839Meni...
British Post Office's number one cat Tibs the GreatTibs in 1953Other name(s)TibsSpeciesCatSexMaleBornNovember 1950London, EnglandDiedDecember 1964LondonOccupationBritish Post Office's number one catYears active1950–1964OwnerAlf TalbutParent(s)Minnie (mother) Tibs the Great (November 1950 – December 1964) was the British Post Office's number one cat and kept the post office headquarters in London completely mouse-free during his 14 years of service. He was the son of Minnie, and on his dea...
Not to be confused with Romanian Front (World War I); Romanian Front (Russian Empire); or Romanian Front electoral district (Russian Constituent Assembly election, 1917). Political party in Romania Romanian Front Frontul RomânescPresidentAlexandru Vaida-VoevodFoundedMarch 12, 1935DissolvedMarch 30, 1938Split fromNational Peasants' Party (PNȚ)Succeeded byNational Renaissance Front (FRN)HeadquartersElisabeta Boulevard 8, Bucharest[1]NewspaperGazeta TransilvanieiFrontul R...
Recreational watercraft that uses an inboard engine powering a pump-jet with an impeller Jet ski redirects here. For the brand-name watercraft, see Jet Ski. For other uses, see Jet Ski (disambiguation). This article needs additional citations for verification. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed.Find sources: Personal watercraft – news · newspapers · books · scholar �...
Italian luxury car manufacturer This article is about the Italian automobile manufacturer. For Maserati models produced, see List of Maserati vehicles. For other uses of the name, see Maserati (disambiguation). Not to be confused with Mazzanti. Maserati S.p.A.Headquarters in Modena, ItalyTypeSubsidiary (S.p.A.)IndustryAutomotivePredecessorOfficine Alfieri Maserati S.p.A.FoundedDecember 1, 1914; 109 years ago (1914-12-01)Bologna, ItalyFounderAlfieri MaseratiHeadquartersModena...
British TV series or programme The Big ReunionAlso known asThe Big Reunion: On TourThe Big Christmas ReunionGenreRealityCreated byMichael Kelpie[1]Directed byShane ByrneMark DrakeStarring Five 911 Atomic Kitten B*Witched Honeyz Liberty X Blue 3T A1 Damage Eternal Girl Thing 5th Story Narrated byAndi PetersTheme music composerThe Audio FreaksCountry of originUnited KingdomOriginal languageEnglishNo. of series2No. of episodes21 (list of episodes)ProductionExecutive producersMichael...
Penghargaan Guldbagge ke-32Tanggal10 Februari 1997TempatSwediaSorotanFilm TerbaikHansumPenghargaan terbanyakHansum (4)Nominasi terbanyakJägarna (6) ← 31 Penghargaan Guldbagge 33 → Acara Penghargaan Guldbagge ke-32, yang dipersembahkan oleh Institut Film Swedia, menghargai film-film Swedia terbaik dari tahun 1996, dan diadakan pada 10 Februari 1997. Hansum garapan Erik Crone dipersembahkan dengan penghargaan untuk Film Terbaik. Catatan dan referensi Pranala luar Situs we...
The L Street Bridge in 2015 Aerial view of the L Street Bridge, at center, 1973 The L Street Bridge is a bridge carrying the Rock Creek and Potomac Parkway over Rock Creek in Washington, D.C. It is the most downstream of three bridges where the Parkway switches from one side of the river to the other, the others being the bridge near P Street and the Shoreham Hill Bridge.[1] Despite its name, the bridge does not carry or cross L Street, but it is adjacent to L Street's western terminu...
Secretaría de Educación, Ciencia, Tecnología e Innovación de la Ciudad de México Secretaría de Educación, Ciencia, Tecnología e Innovación de la Ciudad de México LocalizaciónPaís México MéxicoInformación generalSigla SECTEIJurisdicción Ciudad de MéxicoTipo ministerio de EducaciónSede Ciudad de MéxicoAv Chapultepec 49, Colonia Centro, Centro, 06010 Ciudad de MéxicoOrganizaciónSecretaria Jesús Ofelia Angulo GuerreroDepende de Gobierno de la Ciudad de MéxicoEntidad...
Một con tê tê (Manis pentadactyla) tại Vườn thú Leipzig Phân bố các loài tê tê:Manis crassicaudata - tímManis pentadactyla - camManis javanica - cyanManis culionensis - đỏPhataginus tricuspis - xanh lá cây vàngPhataginus tetradactyla - magentaSmutsia gigantea - greenSmutsia temmenicki - xanh dương Nạn buôn bán tê tê là việc săn trộm, buôn bán trái phép tê tê, các bộ phận của tê tê, hoặc các sản phẩm có nguồn gốc tê tê. Tê tê...
Eurovision Song Contest 2005Country GreeceNational selectionSelection processArtist: Internal selectionSong: Eurovision PartySelection date(s)Artist: 22 January 2005Song: 2 March 2005Selected entrantHelena PaparizouSelected songMy Number OneSelected songwriter(s)Manos PsaltakisChristos DantisNatalia GermanouFinals performanceFinal result1st, 230 pointsGreece in the Eurovision Song Contest ◄2004 • 2005 • 2006► Greece won the Eurovision Song Contest 20...
Esta página ou seção foi marcada para revisão devido a incoerências ou dados de confiabilidade duvidosa. Se tem algum conhecimento sobre o tema, por favor, verifique e melhore a coerência e o rigor deste artigo.Considere colocar uma explicação mais detalhada na discussão. Esta página cita fontes, mas que não cobrem todo o conteúdo. Ajude a inserir referências. Conteúdo não verificável pode ser removido.—Encontre fontes: ABW • CAPES • Google ...
2017 American psychological thriller streaming television series For other uses, see Gypsy (disambiguation). GypsyPromotional posterGenre Drama Psychological thriller Created byLisa RubinStarring Naomi Watts Billy Crudup Sophie Cookson Lucy Boynton Karl Glusman Melanie Liburd Poorna Jagannathan Brenda Vaccaro Brooke Bloom Opening themeGypsy by Stevie NicksCountry of originUnited StatesOriginal languageEnglishNo. of seasons1No. of episodes10ProductionExecutive producers Lisa Rubin Liza Chasin ...
Conflict between Sri lanka and LTTE separatists Main article: Sri Lankan Civil War The neutrality of this article is disputed. Relevant discussion may be found on the talk page. Please do not remove this message until conditions to do so are met. (November 2020) (Learn how and when to remove this template message) Eelam War IVPart of the Sri Lankan Civil WarThe area of Sri Lanka claimed by the LTTE as Tamil Eelam, where the vast majority of the fighting took placeDate26 July 2006 – 18 May 2...
Un pestiño. Bandeja de pestiños. El pestiño —del latín pistus: «majado», «batido»— es un tipo de fruta de sartén que se suele servir como dulce navideño o de Semana Santa, típico de Andalucía y otras zonas de España, elaborado con masa de harina, frito en aceite de oliva y pasado por miel.[1][2] Historia La historia del pestiño puede remontarse al menos hasta el siglo XVI, siendo probablemente mucho más antiguo. La primera referencia literaria la encontra...
Coastal region of Spain This article needs additional citations for verification. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed.Find sources: Costa de Almería – news · newspapers · books · scholar · JSTOR (January 2021) (Learn how and when to remove this template message) Costa de Almeríaclass=notpageimage| Costa de Almería Playa de Mónsul, in the Cabo de Gata-Níjar Natur...