Стандартный ML - Википедия - Standard ML
Парадигма | Мультипарадигма: функциональный, императив, модульный[1] |
---|---|
Семья | ML |
Впервые появился | 1983[2] |
Стабильный выпуск | Стандартный ML '97[2] / 1997 |
Печатная дисциплина | Предполагаемый, статический, сильный |
Расширения имени файла | .sml |
Интернет сайт | sml-семья |
Основной реализации | |
SML / NJ, MLton | |
Диалекты | |
Алиса, Параллельный ML, Зависимый ML | |
Под влиянием | |
ML, Надеяться, Паскаль | |
Под влиянием | |
Вяз, F #, F *, Haskell, OCaml, Python,[3] Ржавчина, Scala |
Стандартный ML (SML) является универсальным, модульный, функциональный язык программирования с проверка типов во время компиляции и вывод типа. Он популярен среди компилятор писатели и исследователи языков программирования, а также в разработке средства доказательства теорем.
SML - это современный диалект ML, язык программирования, используемый в Логика для вычислимых функций (LCF) проект доказательства теорем. Он отличается от широко используемых языков тем, что имеет формальную спецификацию, представленную как правила набора текста и операционная семантика в Определение стандартного машинного обучения.[4]
Язык
Стандартный ML - это функциональный язык программирования с некоторыми нечистыми функциями. Программы, написанные на Standard ML, состоят из выражения для оценки, в отличие от операторов или команд, хотя некоторые выражения возвращают тривиальное "единичное" значение и оцениваются только на предмет их побочных эффектов.
Как и все языки функционального программирования, ключевой особенностью Standard ML является функция, который используется для абстракции. Например, факториал функция может быть выражена как:
весело факториал п = если п = 0 тогда 1 еще п * факториал (п - 1)
Для определения статического типа требуется стандартный компилятор ML. интервал -> интервал
этой функции без аннотаций типов, предоставляемых пользователем. Т.е. он должен вывести, что п используется только с целочисленными выражениями и, следовательно, сам должен быть целым числом, и что все выражения, производящие значение, внутри функции возвращают целые числа.
Эту же функцию можно выразить с помощью определения клаузальной функции где если-тогда-еще Условное выражение заменяется последовательностью шаблонов факториальной функции, оцениваемых для определенных значений, разделенных символом '|', которые проверяются один за другим в записанном порядке, пока не будет найдено совпадение:
весело факториал 0 = 1 | факториал п = п * факториал (п - 1)
Это можно переписать, используя оператор case следующим образом:
вал rec факториал = fn п => дело п из 0 => 1 | п => п * факториал (п - 1)
или итеративно:
весело factorialIT ценить =позволять вал флаг = ссылка ценить и я = ссылка 1в пока !флаг <> 0 делать ( я := !я * !флаг; флаг := !флаг - 1 ); !яконец;
или как лямбда-функция:
вал rec факториал = fn 0 => 1 | п => п * факториал(п - 1)
Здесь ключевое слово вал
вводит привязку идентификатора к значению, fn
вводит определение анонимная функция, и дело
вводит последовательность шаблонов и соответствующих выражений.
Используя локальную функцию, эту функцию можно переписать на более эффективный хвостовой рекурсивный стиль.
весело факториал п = позволять весело lp (0, соотв) = соотв | lp (м, соотв) = lp (м-1, м * соотв) в lp (п, 1) конец
(Значение позволять-выражение - это выражение между в и конец.) Инкапсуляция сохраняющего инвариант хвостово-рекурсивного жесткого цикла с одним или несколькими параметрами-накопителями внутри не содержащей инвариантов внешней функции, как показано здесь, является распространенной идиомой в стандартном ML и с большой частотой появляется в коде SML.
Синонимы типа
Синоним типа определяется с помощью тип ключевое слово. Вот синоним типа для точек на плоскости и функций, вычисляющих расстояния между двумя точками и площадь треугольника с заданными углами согласно Формула Герона. (Эти определения будут использоваться в следующих примерах).
тип место = настоящий * настоящий весело расстояние ((x0, y0), (x1, y1)) = позволять вал dx = x1 - x0 вал dy = y1 - y0 в Математика.sqrt (dx * dx + dy * dy) конец весело цапля (а, б, c) = позволять вал ab = расстояние (а, б) вал до н.э = расстояние (б, c) вал ac = расстояние (а, c) вал перим = ab + до н.э + ac вал s = перим / 2.0 в Математика.sqrt (s * (s - ab) * (s - до н.э) * (s - ac)) конец
Алгебраические типы данных и сопоставление с образцом
Стандартный ML обеспечивает надежную поддержку алгебраические типы данных (короче ADT). Тип данных ML можно рассматривать как несвязный союз кортежей (или «сумма произведений»). Их легко определить и с ними легко программировать, во многом благодаря стандартному машинному обучению. сопоставление с образцом а также проверку полноты и избыточности шаблонов в большинстве реализаций Standard ML.
Тип данных определяется с помощью тип данных ключевое слово, как в
тип данных форма = Круг из место * настоящий (* центр и радиус *) | Квадрат из место * настоящий (* верхний левый угол и длина стороны; с выравниванием по оси *) | Треугольник из место * место * место (* углы *)
(См. Определение место
.) Примечание: для определения рекурсивных конструкторов необходимы типы данных, а не синонимы типов. (В данном примере это не проблема.)
Порядок имеет значение в сопоставлении с образцом: сначала пробуются образцы, которые сначала отображаются в тексте. Сопоставление с образцом может быть синтаксически встроено в определения функций следующим образом:
весело площадь (Круг (_, р)) = 3.14 * р * р | площадь (Квадрат (_, s)) = s * s | площадь (Треугольник (а, б, c)) = цапля (а, б, c) (* см. выше *)
Обратите внимание, что подкомпоненты, значения которых не требуются в конкретном вычислении, опускаются с помощью подчеркивания или так называемых шаблонов подстановки.
Определение функции в стиле так называемой "клаузальной формы", в которой шаблоны появляются сразу после имени функции, просто синтаксический сахар за
весело площадь форма = дело форма из Круг (_, р) => 3.14 * р * р | Квадрат (_, s) => s * s | Треугольник (а, б, c) => цапля (а, б, c)
Проверка полноты шаблона обеспечит учет каждого случая типа данных и выдаст предупреждение, если нет. Следующая закономерность неисчерпаема:
весело центр (Круг (c, _)) = c | центр (Квадрат ((Икс, у), s)) = (Икс + s / 2.0, у + s / 2.0)
Нет шаблона для Треугольник
дело в центр
функция. Компилятор выдаст предупреждение о том, что шаблон неисчерпаем, и если во время выполнения Треугольник
передается в эту функцию, исключение Матч
будет поднят.
Набор предложений в следующем определении функции является исчерпывающим и не является избыточным:
весело hasCorners (Круг _) = ложный | hasCorners _ = истинный
Если контроль проходит мимо первого шаблона ( Круг
), мы знаем, что значение должно быть либо Квадрат
или Треугольник
. В любом из этих случаев мы знаем, что у фигуры есть углы, поэтому можем вернуть истинный
не различая, в каком случае мы находимся.
Шаблон во втором предложении следующей (бессмысленной) функции является избыточным:
весело ж (Круг ((Икс, у), р)) = х + у | ж (Круг _) = 1.0 | ж _ = 0.0
Любое значение, которое соответствует шаблону во втором предложении, также будет соответствовать шаблону в первом предложении, поэтому второе предложение недостижимо. Следовательно, это определение в целом демонстрирует избыточность и вызывает предупреждение во время компиляции.
Программисты на C могут использовать отмеченные союзы, отправка значений тегов, чтобы выполнить то, что выполняет ML с типами данных и сопоставлением с образцом. Тем не менее, хотя программа C, снабженная соответствующими проверками, будет в определенном смысле столь же надежна, как соответствующая программа ML, эти проверки обязательно будут динамическими; ML предоставляет набор статических проверок, которые дают программисту высокую степень уверенности в правильности программы во время компиляции.
Обратите внимание, что в объектно-ориентированных языках программирования, таких как Java, несвязанное объединение может быть выражено путем проектирования иерархии классов. Однако, в отличие от иерархии классов, ADT закрыто. Это делает ADT расширяемым способом, ортогональным расширяемости иерархий классов. Иерархии классов могут быть расширены новыми подклассами, но не новыми методами, в то время как ADT могут быть расширены для обеспечения нового поведения для всех существующих конструкторов, но не позволяют определять новые конструкторы.
Функции высшего порядка
Функции могут использовать функции в качестве аргументов:
весело applyToBoth ж Икс у = (ж Икс, ж у)
Функции могут создавать функции как возвращаемые значения:
весело constantFn k = позволять весело const что-либо = k в const конец
(альтернативно)
весело constantFn k = (fn что-либо => k)
Функции также могут как потреблять, так и производить функции:
весело сочинять (ж, грамм) = позволять весело час Икс = ж (грамм Икс) в час конец
(альтернативно)
весело сочинять (ж, грамм) = (fn Икс => ж (грамм Икс))
Функция List.map
из базовой библиотеки - одна из наиболее часто используемых функций высшего порядка в Standard ML:
весело карта _ [] = [] | карта ж (x :: xs) = ж Икс :: карта ж хз
(Более эффективная реализация карта
определил бы хвостовой рекурсивный внутренний цикл следующим образом :)
весело карта ж хз = позволять весело м ([], соотв) = Список.rev соотв | м (x :: xs, соотв) = м (хз, ж Икс :: соотв) в м (хз, []) конец
Исключения
Исключения возникают с поднимать
ключевое слово и обрабатывается с сопоставлением с образцом ручка
конструкции.
исключение Неопределенный весело Максимум [Икс] = Икс | Максимум (x :: xs) = позволять вал м = Максимум хз в если Икс > м тогда Икс еще м конец | Максимум [] = поднимать Неопределенный весело главный хз = позволять вал сообщение = (Int.нанизывать (Максимум хз)) ручка Неопределенный => "пустой список ... нет максимума!" в Распечатать (сообщение ^ " п") конец
Систему исключений можно использовать для реализации нелокальный выход, метод оптимизации, подходящий для следующих функций.
исключение Нуль весело listProd нс = позволять весело п [] = 1 | п (0::_) = поднимать Нуль | п (h :: t) = час * п т в (п нс) ручка Нуль => 0 конец
Когда исключение Нуль
повышается в случае 0, управление оставляет функцию п
все вместе. Рассмотрим альтернативу: значение 0 будет возвращено в самый последний ожидающий кадр, оно будет умножено на локальное значение час
, результирующее значение (неизбежно 0) будет возвращено, в свою очередь, следующему ожидающему кадру и так далее. Возникновение исключения позволяет обойти управление непосредственно по всей цепочке кадров и избежать связанных вычислений. Следует отметить, что такая же оптимизация могла быть получена с помощью хвостовой рекурсии для этого примера.
Модульная система
Стандартный ML имеет расширенный модуль система, позволяющая разложить программы на иерархически организованные структуры логически связанных объявлений типов и значений. Модули SML обеспечивают не только пространство имен контроля, но также и абстракцию в том смысле, что они позволяют программистам определять абстрактные типы данных.
Систему модулей SML составляют три основные синтаксические конструкции: структуры, сигнатуры и функторы. А структура это модуль; он состоит из набора типов, исключений, значений и структур (называемых подконструкции) упакованы вместе в логическую единицу. А подпись является интерфейс, обычно рассматривается как тип структуры: он определяет имена всех сущностей, предоставляемых структурой, а также арности компонентов типов, типов компонентов значений и сигнатур для подструктур. Определения компонентов типа можно экспортировать или не экспортировать; компоненты типа, определения которых скрыты, абстрактные типы. Наконец, функтор это функция от структур к структурам; то есть функтор принимает один или несколько аргументов, которые обычно являются структурами данной сигнатуры, и в качестве своего результата создает структуру. Функторы используются для реализации общий структуры данных и алгоритмы.
Например, подпись для очередь структура данных может быть:
подпись ОЧЕРЕДЬ = сиг тип 'а очередь исключение QueueError вал пустой : 'а очередь вал пусто : 'а очередь -> bool вал одиночка : 'а -> 'а очередь вал вставлять : 'а * 'а очередь -> 'а очередь вал заглядывать : 'а очередь -> 'а вал удалять : 'а очередь -> 'а * 'а очередь конец
Эта подпись описывает модуль, который предоставляет параметризованный тип очередь
очередей, исключение называется QueueError
, и шесть значений (пять из которых являются функциями), обеспечивающие основные операции с очередями. Теперь можно реализовать структуру данных очереди, написав структуру с этой подписью:
структура TwoListQueue :> ОЧЕРЕДЬ = структура тип 'а очередь = 'а список * 'а список исключение QueueError вал пустой = ([],[]) весело пусто ([],[]) = истинный | пусто _ = ложный весело одиночка а = ([], [а]) весело вставлять (а, ([], [])) = ([], [а]) | вставлять (а, (ins, выходы)) = (a :: ins, выходы) весело заглядывать (_,[]) = поднимать QueueError | заглядывать (ins, a :: out) = а весело удалять (_,[]) = поднимать QueueError | удалять (ins, [а]) = (а, ([], rev ins)) | удалять (ins, a :: out) = (а, (ins,выходы)) конец
Это определение заявляет, что TwoListQueue
это реализация ОЧЕРЕДЬ
подпись. Кроме того, непрозрачное приписывание (обозначается :>
) утверждает, что любые компоненты типа, определения которых не представлены в сигнатуре (т.е. очередь
) следует рассматривать как абстрактные, что означает, что определение очереди как пары списков не видно за пределами модуля. Тело структуры обеспечивает привязки для всех компонентов, перечисленных в подписи.
Чтобы использовать структуру, можно получить доступ к ее членам типа и значения, используя "точечную нотацию". Например, очередь строк будет иметь тип строка TwoListQueue.queue
, пустая очередь TwoListQueue.empty
, и чтобы удалить первый элемент из очереди с именем q
можно было бы написать TwoListQueue.remove q
.
Один популярный алгоритм[5] за поиск в ширину деревьев использует очереди. Здесь мы представляем версию этого алгоритма, параметризованную по абстрактной структуре очереди:
функтор BFS (структура Q: ОЧЕРЕДЬ) = (* по Окасаки, ICFP, 2000 *) структура тип данных 'а дерево = E | Т из 'а * 'а дерево * 'а дерево весело bfsQ (q : 'а дерево Q.очередь) : 'а список = если Q.пусто q тогда [] еще позволять вал (т, q ') = Q.удалять q в дело т из E => bfsQ q ' | Т (Икс, л, р) => позволять вал q '' = Q.вставлять (р, Q.вставлять (л, q ')) в Икс :: bfsQ q '' конец конец весело бойфренды т = bfsQ (Q.одиночка т) конец
Обратите внимание, что внутри BFS
структура, программа не имеет доступа к конкретному представлению очереди в игре. Более конкретно, программа не может, скажем, выбрать первый список в представлении очереди с двумя списками, если это действительно используется представление. Этот абстракция данных механизм делает код в ширину действительно независимым от выбора представления очереди. Это в общем случае желательно; в данном случае структура очереди может безопасно поддерживать любой из различных логических инвариантов, от которых зависит ее правильность за пуленепробиваемой стеной абстракции.
Библиотеки
Стандарт
Базовая библиотека SML стандартизирована и поставляется с большинством реализаций. Он предоставляет модули для деревьев, массивов и других структур данных, а также интерфейсы ввода / вывода и системы.
Третья сторона
Для численных вычислений существует модуль Matrix (но в настоящее время он не работает), https://www.cs.cmu.edu/afs/cs/project/pscico/pscico/src/matrix/README.html.
Для графики cairo-sml - это интерфейс с открытым исходным кодом для Каир графическая библиотека.
Для машинного обучения существует библиотека графических моделей.
Примеры кода
Фрагменты кода SML легче всего изучать, вводя их в "верхний уровень", также известный как цикл чтения-оценки-печати или REPL. Это интерактивный сеанс, который печатает предполагаемые типы результирующих или определенных выражений. Многие реализации SML предоставляют интерактивный REPL, включая SML / NJ:
$ sml Стандартный ML Нью-Джерси v110.52 [построено: 21 января, пт, 16:42:10 2005] -
Затем можно ввести код в ответ на приглашение «-». Например, чтобы вычислить 1 + 2 * 3:
- 1 + 2 * 3; вал Это = 7 : int
Верхний уровень определяет тип выражения как «int» и возвращает результат «7».
Привет, мир
Следующая программа "hello.sml":
Распечатать "Привет, мир! п";
может быть скомпилирован с помощью MLton:
$ mlton hello.sml
и выполнено:
$ ./hello Привет, мир!
Вставка сортировки
Сортировка вставкой для списков целых чисел (по возрастанию) кратко выражается следующим образом:
весело ins (п, []) = [п] | ins (п, нс в качестве h :: t) = если (п <ч) тогда n :: ns еще час::(ins (п, т)) вал InsertSort = Список.складной ins []
Это можно сделать полиморфным, абстрагируясь от оператора упорядочивания. Здесь мы используем символическое имя <<
для этого оператора.
весело ins ' << (число, числа) = позволять весело я (п, []) = [п] | я (п, нс в качестве h :: t) = если <<(п,час) тогда n :: ns еще Здравствуй(п,т) в я (число, числа) конец весело InsertSort ' << = Список.складной (ins ' <<) []
Тип InsertSort '
является ('a *' a -> bool) -> ('список) -> (' список)
.
Пример вызова:
- InsertSort ' op< [3, 1, 4];вал Это = [1,3,4] : int список
Сортировка слиянием
Здесь классический алгоритм сортировки слиянием реализован в трех функциях: разделение, слияние и сортировка слиянием.
Функция расколоть
реализован с помощью локальной функции с именем петля
, который имеет два дополнительных параметра. Локальная функция петля
написано в хвостовой рекурсивный стиль; как таковой его можно эффективно компилировать. Эта функция использует синтаксис сопоставления с образцом SML, чтобы различать непустые списки (x :: xs
) и пустой список ([]
) случаи. Для стабильности список ввода нс
отменяется перед передачей в петля
.
(* Разделить список на две половины, возвращается как пара. * «Половинки» будут одного размера, * или в первом будет на один элемент больше, чем во втором. * Выполняется за время O (n), где n = | xs |. *) местный весело петля (x :: y :: zs, хз, ys) = петля (zs, x :: xs, y :: ys) | петля (Икс::[], хз, ys) = (x :: xs, ys) | петля ([], хз, ys) = (хз, ys) в весело расколоть нс = петля (Список.rev нс, [], []) конец
Синтаксис local-in-end можно заменить синтаксисом let-in-end, что даст эквивалентное определение:
весело расколоть нс = позволять весело петля (x :: y :: zs, хз, ys) = петля (zs, x :: xs, y :: ys) | петля (Икс::[], хз, ys) = (x :: xs, ys) | петля ([], хз, ys) = (хз, ys) в петля (Список.rev нс, [], []) конец
Как и в случае разделения, слияние также использует для повышения эффективности локальный цикл функций. Внутренний петля
определяется в терминах случаев: когда передаются два непустых списка, когда передается один непустой список и когда передаются два пустых списка. Обратите внимание на использование подчеркивания (_
) как шаблон подстановки.
Эта функция объединяет два «восходящих» списка в один восходящий список. Обратите внимание, как аккумулятор из
строится "задом наперед", а затем переворачивается List.rev
перед возвращением. Это распространенный метод - составьте список в обратном порядке, а затем переверните его перед возвратом. В SML списки представлены как связанный список кончает, и поэтому эффективно добавлять элемент к списку, но неэффективно добавлять элемент в список. Дополнительный проход по списку - это линейное время операция, поэтому, хотя этот метод требует больше времени настенных часов, асимптотика не хуже.
(* Объедините два упорядоченных списка, используя порядок lt. * Pre: указанные списки xs и ys уже должны быть упорядочены по lt. * Выполняется за время O (n), где n = | xs | + | ys |. *) весело слияние lt (хз, ys) = позволять весело петля (из, оставили в качестве x :: xs, верно в качестве y :: ys) = если lt (Икс, у) тогда петля (x :: out, хз, верно) еще петля (Вы т, оставили, ys) | петля (из, x :: xs, []) = петля (x :: out, хз, []) | петля (из, [], y :: ys) = петля (Вы т, [], ys) | петля (из, [], []) = Список.rev из в петля ([], хз, ys) конец
Основная функция.
(* Сортировать список в соответствии с заданной операцией упорядочивания lt. * Выполняется за время O (n log n), где n = | xs |. *) весело Сортировка слиянием lt хз = позволять вал слияние ' = слияние lt весело РС [] = [] | РС [Икс] = [Икс] | РС хз = позволять вал (оставили, верно) = расколоть хз в слияние ' (РС оставили, РС верно) конец в РС хз конец
Также обратите внимание, что в коде не упоминаются типы переменных, за исключением синтаксиса :: и [], обозначающего списки. Этот код будет сортировать списки любого типа, если можно определить последовательную функцию упорядочивания lt. С помощью Вывод типа Хиндли-Милнера, компилятор может определить типы всех переменных, даже сложных типов, таких как функция lt.
Быстрая сортировка
Быструю сортировку можно выразить следующим образом. Эта общая быстрая сортировка использует оператор заказа <<
.
весело быстрая сортировка << хз = позволять весело qs [] = [] | qs [Икс] = [Икс] | qs (p :: xs) = позволять вал (меньше, более) = Список.раздел (fn Икс => << (Икс, п)) хз в qs меньше @ п :: qs более конец в qs хз конец
Написание языкового переводчика
Обратите внимание на относительную легкость, с которой язык малых выражений определяется и обрабатывается.
исключение Err тип данных ты = IntTy | BoolTy тип данных exp = Истинный | Ложь | Int из int | Нет из exp | Добавлять из exp * exp | Если из exp * exp * exp весело тип (Истинный) = BoolTy | тип (Ложь) = BoolTy | тип (Int _) = IntTy | тип (Нет е) = если тип е = BoolTy тогда BoolTy еще поднимать Err | тип (Добавлять (e1, e2)) = если (тип e1 = IntTy) а также (тип e2 = IntTy) тогда IntTy еще поднимать Err | тип (Если (e1, e2, e3)) = если тип e1 <> BoolTy тогда поднимать Err еще если тип e2 <> тип e3 тогда поднимать Err еще тип e2 весело оценка (Истинный) = Истинный | оценка (Ложь) = Ложь | оценка (Int п) = Int п | оценка (Нет е) = (дело оценка е из Истинный => Ложь | Ложь => Истинный | _ => поднимать Провал "проверка типов нарушена") | оценка (Добавлять (e1, e2)) = позволять вал (Int n1) = оценка e1 вал (Int n2) = оценка e2 в Int (n1 + n2) конец | оценка (Если (e1, e2, e3)) = если оценка e1 = Истинный тогда оценка e2 еще оценка e3 весело chkEval е = (игнорировать (тип е); оценка е) (* вызовет Err при ошибке типа *)
Пример использования на правильно набранных и неправильно набранных примерах:
- вал e1 = Добавлять(Int(1), Int(2)); (* Правильно напечатано *)вал e1 = Добавлять (Int 1,Int 2) : exp- chkEval e1;вал Это = Int 3 : exp- вал e2 = Добавлять(Int(1),Истинный); (* Напечатано неправильно *)вал e2 = Добавлять (Int 1,Истинный) : exp- chkEval e2;непойманный исключение Err
Факториальная функция произвольной точности (библиотеки)
В SML модуль IntInf обеспечивает арифметические операции с целыми числами произвольной точности. Более того, целочисленные литералы могут использоваться как целые числа произвольной точности, при этом программисту ничего не нужно делать.
Следующая программа "fact.sml" реализует факториал произвольной точности и выводит факториал 120:
весело факт п : IntInf.int = если п=0 тогда 1 еще п * факт(п - 1) вал () = Распечатать (IntInf.нанизывать (факт 120) ^ " п")
и может быть скомпилирован и запущен с помощью:
$ mlton fact.sml$ ./факт6689502913449127057588118054090372586752746333138029810295671352301633557244962989366874165271984981308157637893214090552534408589408121859898481114389650005964960521256960000000000000000000000000000
Числовая производная (функции высшего порядка)
Поскольку SML является функциональным языком программирования, в программах SML легко создавать и передавать функции. Эта возможность имеет огромное количество приложений. Вычисление числовой производной функции - одно из таких приложений. Следующая функция SML "d" вычисляет числовую производную заданной функции "f" в заданной точке "x":
- весело d дельта ж Икс = (ж (Икс + дельта) - ж (Икс - дельта)) / (2.0 * дельта); вал d = fn : настоящий -> (настоящий -> настоящий) -> настоящий -> настоящий
Эта функция требует небольшого значения «дельта». Хорошим выбором для дельты при использовании этого алгоритма является кубический корень из машина эпсилон.[нужна цитата ]
Тип функции "d" указывает, что она отображает "float" на другую функцию с типом "(real -> real) -> real -> real". Это позволяет нам частично применять аргументы. Этот функциональный стиль известен как карри. В этом случае полезно частично применить первый аргумент «дельта» к «d», чтобы получить более специализированную функцию:
- вал d = d 1E ~ 8; вал d = fn : (настоящий -> настоящий) -> настоящий -> настоящий
Обратите внимание, что предполагаемый тип указывает, что замена «d» ожидает функцию с типом «real -> real» в качестве первого аргумента. Мы можем вычислить численное приближение к производной от в с:
- d (fn Икс => Икс * Икс * Икс - Икс - 1.0) 3.0; вал Это = 25.9999996644 : настоящий
Правильный ответ ; .
Функция «d» называется «функцией высшего порядка», потому что она принимает другую функцию («f») в качестве аргумента.
Каррированные функции и функции более высокого порядка могут использоваться для устранения избыточного кода. Например, для библиотеки могут потребоваться функции типа а -> б
, но удобнее писать функции типа а * в -> б
где существует фиксированная связь между объектами типа а
и c
. Функция высшего порядка типа (a * c -> b) -> (a -> b) может исключить эту общность. Это пример шаблон адаптера.[нужна цитата ]
Дискретное вейвлет-преобразование (сопоставление с образцом)
1D Вейвлет Хаара преобразовать из целое число Список чисел в степени двойки может быть очень кратко реализован в SML и является отличным примером использования сопоставление с образцом над списками, беря пары элементов («h1» и «h2») с фронта и сохраняя их суммы и разности в списках «s» и «d» соответственно:
- весело хаар л = позволять весело вспомогательный [s] [] d = s :: d | вспомогательный [] s d = вспомогательный s [] d | вспомогательный (h1 :: h2 :: t) s d = вспомогательный т (h1 + h2 :: s) (h1-h2 :: d) | вспомогательный _ _ _ = поднимать Пустой в вспомогательный л [] [] конец; вал хаар = fn : int список -> int список
Например:
- хаар [1, 2, 3, 4, ~4, ~3, ~2, ~1]; вал Это = [0,20,4,4,~1,~1,~1,~1] : int список
Сопоставление с образцом - полезная конструкция, позволяющая четко и кратко представить сложные преобразования. Более того, компиляторы SML превращают совпадения шаблонов в эффективный код, в результате чего программы становятся не только короче, но и быстрее.
Реализации
Существует множество реализаций SML, в том числе:
- Стандартный ML Нью-Джерси (сокращенно SML / NJ) - это полный компилятор со связанными библиотеками, инструментами, интерактивной оболочкой и документацией. [1]
- Москва МЛ это облегченная реализация, основанная на CAML Light двигатель времени выполнения. Он реализует полный язык SML, включая модули SML и большую часть базовой библиотеки SML. [2]
- MLton это оптимизация всей программы компилятор, который производит очень быстрый код по сравнению с другими реализациями ML. [3]
- В Комплект ML интегрирует сборщик мусора (который можно отключить) и региональное управление памятью с автоматическим определением регионов для поддержки приложений в реальном времени. Его реализация очень близко основана на Определении.
- Поли / ML представляет собой полную реализацию Standard ML, которая создает быстрый код и поддерживает многоядерное оборудование (через потоки Posix); его система времени выполнения выполняет параллельную сборку мусора и онлайн-совместное использование неизменяемых подструктур.
- Изабель / мл. интегрирует параллельный Poly / ML в интерактивное средство доказательства теорем со сложной IDE (на основе jEdit ) для официального стандарта ML (SML'97), диалекта Isabelle / ML и языка проверки. Начиная с Isabelle2016, существует также отладчик исходного кода для ML.
- CakeML[6] версия ML цикла чтения-оценки-печати с формально проверенной средой выполнения и переводом на ассемблер
- Гамлет - это интерпретатор SML, который призван быть точной и доступной эталонной реализацией стандарта.
- НАКЛОН это полноценный сертифицирующий компилятор для SML. Он использует типизированные промежуточные языки для оптимизации кода и обеспечения правильности и может компилироваться в Типизированный язык ассемблера.
- SML.NET позволяет компилировать в Microsoft CLR и имеет расширения для связи с другими .СЕТЬ код.
- SML2c - это пакетный компилятор, который компилирует только объявления уровня модуля (т.е. подписи, структуры, функторы) в C. Он основан на SML / NJ версии 0.67 и имеет общий интерфейс и большую часть своей системы времени выполнения, но не поддерживает отладку и профилирование в стиле SML / NJ. Программы уровня модуля, которые выполняются на SML / NJ, могут компилироваться sml2c без изменений.
- В Поплог система реализует версию SML, с ПОП-11, и необязательно Common Lisp, и Пролог, позволяющий программировать на разных языках. Для всех языком реализации является POP-11, который компилируется постепенно. Он также имеет встроенный Emacs -подобный редактор, взаимодействующий с компилятором.
- SML № является расширением SML, обеспечивающим полиморфизм записей и взаимодействие с языком C. Это обычный собственный компилятор, и его имя нет намек на работу на платформе .NET.
- Алиса: интерпретатор Standard ML от Саарландского университета, добавляющий функции для ленивая оценка, параллелизм (многопоточность и распределенных вычислений через вызовы удаленных процедур ) и программирование в ограничениях.
- SOSML это реализация SML, написанная на Машинопись который запускается непосредственно в веб-браузере. Он реализует большую часть языка SML и отдельные части базовой библиотеки SML.
Все эти реализации Открытый исходный код и в свободном доступе. Большинство из них реализованы на SML. Коммерческих реализаций SML больше нет. Арлекин когда-то создал коммерческую IDE и компилятор для SML под названием MLWorks. Компания сейчас не существует. MLWorks перешел к Xanalys и позже был приобретен Ravenbrook Limited на 2013-04-26 и с открытым исходным кодом.
Основные проекты с использованием SML
В ИТ-университет Копенгагена весь архитектура предприятия реализована примерно в 100 000 строк SML, включая записи о персонале, платежную ведомость, администрирование курсов и обратную связь, управление студенческими проектами и веб-интерфейсы самообслуживания.[7]
В HOL4 и Изабель помощники по доказательству написаны на SML.
SML широко используется разработчиками компиляторов и микросхем, например РУКА.[нужна цитата ]
Смотрите также
Рекомендации
- ^ «Программирование в стандартном машинном обучении: иерархии и параметризация». Получено 2020-02-22.
- ^ а б "SML '97". www.smlnj.org.
- ^ "itertools - Функции, создающие итераторы для эффективного цикла - Документация Python 3.7.1rc1". docs.python.org.
- ^ Милнер, Робин; Тофте, Мэдс; Харпер, Роберт; Маккуин, Дэвид (1997). Определение Standard ML (пересмотренное). MIT Press. ISBN 0-262-63181-4.
- ^ Окасаки, Крис (2000). «Нумерация в ширину: уроки из небольшого упражнения в разработке алгоритмов». Международная конференция по функциональному программированию 2000 г.. ACM.
- ^ «CakeML». cakeml.org.
- ^ Мэдс, Тофте. "Стандартный язык ML". Scholarpedia. Получено 2020-01-08.
внешняя ссылка
- Стандартный проект семейства ML на GitHub
- Стандартный язык ML Мадс Тофте, Scholarpedia, 4(2):7515. DOI: 10.4249 / scholarpedia.7515
- Что такое SML?
- Что такое SML '97?
- преемник ML (sML) предназначен для обеспечения непрерывной эволюции машинного обучения с использованием стандартного машинного обучения в качестве отправной точки.
- Программирование в стандартном ML
- Программирование в Standard ML '97: онлайн-учебник
- Univ. Чикаго - учебник по SML (слайды)
- CSE341: Языки программирования, Дэн Гроссман, Вашингтонский университет. Также на Coursera и YouTube