Miranda — это ленивый , чисто функциональный язык программирования , разработанный Дэвидом Тёрнером в качестве преемника его более ранних языков программирования SASL и KRC , с использованием некоторых концепций ML и Hope . Он был создан английской компанией Research Software Ltd. (владеющей торговой маркой Miranda ) [3] и стал первым чисто функциональным языком, получившим коммерческую поддержку. [ нужна цитата ]
Миранда была впервые выпущена в 1985 году как быстрый интерпретатор C для операционных систем Unix с последующими выпусками в 1987 и 1989 годах. Она оказала сильное влияние на более поздний язык Haskell . [4] Тернер заявил, что преимущества Миранды перед Хаскеллом заключаются в следующем: «Меньший язык, более простая система типов, более простая арифметика». [5]
В 2020 году версия Miranda была выпущена с открытым исходным кодом под лицензией BSD . Код был обновлен для соответствия современным стандартам C ( C11 / C18 ) и для создания 64-битных двоичных файлов. Это было протестировано на операционных системах, включая Debian , Ubuntu , WSL /Ubuntu и macOS ( Catalina ). [5] [6]
Имя Миранда происходит от герундивной формы латинского глагола miror [7] , что означает «достойная восхищения».
На логотипе изображена Джон Уильям Уотерхаус в исполнении персонажа Миранды из шекспировской «Бури» .
Миранда — ленивый , чисто функциональный язык программирования. То есть в нем отсутствуют побочные эффекты и обязательные функции программирования. Программа Миранды (называемая скриптом ) представляет собой набор уравнений , определяющих различные математические функции и алгебраические типы данных . Здесь важен набор слов : порядок уравнений, как правило, не имеет значения, и нет необходимости определять сущность перед ее использованием.
Поскольку алгоритм синтаксического анализа разумно использует макет (отступы с помощью правила off-side ), операторы заключения в скобки используются редко, а терминаторы операторов не нужны. Эта функция, вдохновленная ISWIM , также используется в occam и Haskell и позже была популяризирована Python .
Комментарий вводится в обычный сценарий персонажами ||
и продолжается до конца той же строки. Альтернативное соглашение о комментариях влияет на весь файл исходного кода, известный как « грамотный сценарий », в котором каждая строка считается комментарием, если она не начинается со >
знака.
Базовыми типами данных Миранды являются char
, num
и bool
. Строка символов представляет собой просто список char
, который num
автоматически преобразуется между двумя базовыми формами: целыми числами произвольной точности (также известными как большие числа) по умолчанию и обычными значениями с плавающей запятой по мере необходимости.
Кортежи представляют собой последовательности элементов потенциально смешанных типов, аналогичные записям в языках, подобных Паскалю , и записываются через круглые скобки:
this_employee = ( «Фолланд, Мэри» , 10560 , False , 35 )
Вместо этого список является наиболее часто используемой структурой данных в Миранде. Он записывается в квадратных скобках и с элементами, разделенными запятыми, причем все они должны быть одного типа:
Week_days = [ "Пн" , "Вт" , "Ср" , "Чт" , "Пт" ]
Объединение списков — ++
, вычитание — --
, построение — :
, определение размера — #
и индексирование !
, поэтому:
дни = Week_days ++ [ "Суббота" , "Вс" ] дни = "Ноль" : дни дни ! 0 ⇒ «Ноль» дней = дней -- [ «Ноль» ] # дней ⇒ 7
Существует несколько ярлыков для построения списков: ..
используется для списков, элементы которых образуют арифметическую серию, с возможностью указания приращения, отличного от 1:
fac n = произведение [ 1 .. n ] нечетная_сумма = сумма [ 1 , 3 .. 100 ]
Более общие и мощные средства создания списков предоставляются « пониманиями списков » (ранее известными как «выражения ZF»), которые существуют в двух основных формах: выражение, применяемое к ряду терминов, например:
квадраты = [ п * п | п <- [ 1 .. ] ]
(читается: список n в квадрате, где n берется из списка всех положительных целых чисел) и ряд, в котором каждый член является функцией предыдущего, например:
полномочия_of_2 = [ n | n <- 1 , 2 * n .. ]
Как следует из этих двух примеров, Миранда допускает списки с бесконечным числом элементов, из которых самым простым является список всех положительных целых чисел:[1..]
Обозначение применения функции представляет собой просто сопоставление, как в sin x
.
В Миранде, как и в большинстве других чисто функциональных языков, функции являются первоклассными гражданами, то есть их можно передавать в качестве аргументов другим функциям, возвращать как результаты или включать в качестве элементов структур данных. Более того, функция с двумя или более параметрами может быть «частично параметризована» или каррирована , предоставляя меньше аргументов, чем полное количество параметров. Это дает еще одну функцию, которая, учитывая оставшиеся параметры, вернет результат. Например:
добавить a b = приращение a + b = добавить 1
это обходной способ создания функции «приращение», которая добавляет единицу к своему аргументу. На самом деле add 4 7
берет функцию с двумя параметрами add
, применяет ее для 4
получения функции с одним параметром, которая добавляет четыре к своему аргументу, а затем применяет ее к 7
.
Любую функцию с двумя параметрами (операндами) можно превратить в инфиксный оператор (например, учитывая определение функции add
выше, этот термин $add
во всех отношениях эквивалентен оператору +
), а каждый инфиксный оператор, принимающий два параметра, можно превратить в инфиксный оператор. соответствующая функция. Таким образом:
приращение = ( + ) 1
это самый короткий способ создать функцию, которая добавляет единицу к своему аргументу. Аналогично, в
половина = ( / 2 ) обратная = ( 1 / )
генерируются две однопараметрические функции. Интерпретатор в каждом случае понимает, какой из двух параметров оператора деления предоставляется, предоставляя функции, которые соответственно делят число на два и возвращают обратное значение.
Хотя Miranda является строго типизированным языком программирования , он не требует явного объявления типов . Если тип функции не объявлен явно, интерпретатор определяет его на основе типа ее параметров и того, как они используются внутри функции. В дополнение к базовым типам ( char
, num
, bool
) он включает тип «что угодно», где тип параметра не имеет значения, как в функции обращения списка:
rev [] = [] rev ( a : x ) = rev x ++ [ a ]
который можно применить к списку любого типа данных, для которого явное объявление типа функции будет выглядеть так:
рев :: [ * ] -> [ * ]
Наконец, он имеет механизмы для создания и управления программными модулями , внутренние функции которых невидимы для программ, вызывающих эти модули.
Следующий скрипт Миранды определяет набор всех подмножеств набора чисел.
подмножества [] = [ [] ] подмножества ( x : xs ) = [[ x ] ++ y | y <- ys ] ++ ys где ys = подмножества xs
а это грамотный скрипт для функции primes
, которая выдает список всех простых чисел
> || Бесконечный список всех простых чисел.Список потенциальных простых чисел начинается со всех целых чисел, начиная с 2;при возврате каждого простого числа все следующие числа, которые могут быть в точностиразделенные по нему, отфильтровываются из списка кандидатов.> простые числа = решето [2..]> сито (p:x) = p : сито [n | п <- х; п мод р ~= 0]
Вот еще несколько примеров
max2 :: num -> num -> num max2 a b = a , если a > b = b , иначе max3 :: num -> num -> num -> num max3 a b c = max2 ( max2 a b ) ( max2 a c ) умножить :: num -> num -> num умножить 0 b = 0 умножить a b = b + ( умножить ( a - 1 ) b ) fak :: num -> num fak 0 = 1 fak n = n * fak ( n - 1 ) номер элемента :: [ * ] -> номер номер элемента [] = 0 номер элемента ( a : x ) = 1 + номер элемента x будний день ::= Пн | Вт | Мы | эт | Пт | Сб | Вс isWorkDay :: будний день -> bool isWorkDay Sa = False isWorkDay Su = False isWorkDay Anyday = True дерево * ::= E | N ( дерево * ) * ( дерево * ) количество узлов :: дерево * -> число количество узлов E = 0 количество узлов ( N l w r ) = количество узлов l + 1 + количество узлов r пустой счетчик :: дерево * -> число пустой счетчик E = 1 пустой счетчик ( N l w r ) = пустой счетчик l + пустой счетчик r TreeExample = N ( N ( N E 1 E ) 3 ( N E 4 E )) 5 ( N ( N E 6 E ) 8 ( N E 9 E )) будний деньДерево = N ( N ( N E Mo E ) Вт ( N E Мы E )) Th ( N ( N E Fr E ) Sa ( N E Su )) вставить :: * -> улица * -> улица * вставить x E = N E x E вставить x ( N l w E ) = N l w x вставить x ( N E w r ) = N x w r вставить x ( N l w r ) = вставить x l , если x < w = вставить x r , иначе list2searchtree :: [ * ] -> дерево * list2searchtree [] = E list2searchtree [ x ] = N E x E list2searchtree ( x : xs ) = вставить x ( list2searchtree xs ) maxel :: tree * -> * maxel E = ошибка «пусто» maxel ( N l w E ) = w maxel ( N l w r ) = maxel r minel :: дерево * -> * minel E = ошибка «пустой» minel ( N E w r ) = w minel ( N l w r ) = minel l || Обход : просмотр значений дерева , помещение их в список предварительный заказ , дополнительный заказ , последующий заказ :: дерево * -> [ * ] заказ E = [] заказ N l w r = заказ l ++ [ w ] ++ заказ r предзаказ E = [] предзаказ N l w r = [ w ] ++ предзаказ l ++ предзаказ r постордер E = [] постордер N l w r = постордер l ++ постордер r ++ [ w ] высота :: дерево * -> число высота E = 0 высота ( N l w r ) = 1 + max2 ( высота l ) ( высота r ) сумма :: num -> num сумма x = x , если x >= 0 сумма x = x * ( - 1 ), в противном случае и :: bool -> bool -> bool и True True = True и x y = False || AVL - дерево — это дерево , в котором разница между дочерними узлами не превышает 1 || мне еще нужно это проверить isAvl :: tree * -> bool isAvl E = True isAvl ( N l w r ) = and ( isAvl l ) ( isAvl r ), if sum (( nodecount l ) - ( nodecount r )) < 2 = False , в противном случае удалить :: * -> дерево * -> дерево * удалить x E = E удалить x ( N E x E ) = E удалить x ( N E x r ) = N E ( minel r ) ( удалить ( minel r ) r ) удалить x ( N l x r ) = N ( удалить ( maxel l ) l ) ( maxel l ) r удалить x ( N l w r ) = N ( удалить x l ) w ( удалить x r )