Обзор функциональных языков программирования Lisp, Scheme, Miranda, Haskell, Erlang, ML, Val, Sisal Lisp • Лисп (LISP, от англ. LISt Processing — «обработка списков») — семейство языков программирования, основанных на представлении программы системой линейных списков символов, которые притом являются основной структурой данных языка. • Лисп считается вторым после Фортрана старейшим высокоуровневым языком программирования. Lisp • • • • Common LISP — более навороченный Scheme — более ясный и простой AutoLISP – внутренний язык AutoCAD Common Lisp Object System (CLOS) – объектно-ориентированный Common Lisp • MacLisp, Standard Lisp, SpiceLisp, S-1 Lisp, ZetaLisp, Nil, InterLisp, Emojilisp CLOS Абстракции Переменные экземпляра Методы экземпляра Переменные класса Методы класса Да Да Да Да Инкапсуляция Переменных Методов Чтение, запись, доступ Открытые Модульность Разновидности модулей Пакет Иерархии Наследование Шаблоны Метаклассы Сильная типизация Полиморфизм Множественное Нет Да Возможна Да (множественный) Многозадачность Долгоживущие объекты Да Нет Типизация Параллельность Сохраняемость Common Lisp • CL-USER> (+ 2 3) • 5 • CL-USER> "hello, world" • "hello, world“ • CL-USER> (defun hello-world () (format t "hello, world")) • HELLO-WORLD Common Lisp • (defun verbose-sum (x y) "Sum any two numbers after printing a message." (format t "Summing ~d and ~d.~%" x y) (+ x y)) • • • • (defun foo (a b &optional c d) (list a b c d)) (foo 1 2) ==> (1 2 NIL NIL) (foo 1 2 3) ==> (1 2 3 NIL) (foo 1 2 3 4) ==> (1 2 3 4) Common Lisp • (defun format (stream string &rest values) ...) (defun + (&rest numbers) ...) • • • • • • • • (defun foo (&key a b c) (list a b c)) (foo) ==> (NIL NIL NIL) (foo :a 1) ==> (1 NIL NIL) (foo :b 1) ==> (NIL 1 NIL) (foo :c 1) ==> (NIL NIL 1) (foo :a 1 :c 3) ==> (1 NIL 3) (foo :a 1 :b 2 :c 3) ==> (1 2 3) (foo :a 1 :c 3 :b 2) ==> (1 2 3) Common Lisp • ((lambda (x y) (+ x y)) 2 3) ==> 5 • (defun plot (fn min max step) (loop for i from min to max by step do (loop repeat (funcall fn i) do (format t "*")) (format t "~%"))) (defun double (x) (* 2 x)) CL-USER> (plot #'double 0 10 1) ** **** ****** ******** ********** ************ ************** **************** ****************** ******************** NIL • • • • • • • • • • • • • Common Lisp • (if (> 2 3) "Yup" "Nope") ==> "Nope" • (if (> 2 3) "Yup") ==> NIL • (if (> 3 2) "Yup" "Nope") ==> "Yup" Clojure (require '[clojure.test.check :as tc]) (require '[clojure.test.check.generators :as gen]) (require '[clojure.test.check.properties :as prop]) (def sort-idempotent-prop (prop/for-all [v (gen/vector gen/int)] (= (sort v) (sort (sort v))))) (tc/quick-check 100 sort-idempotent-prop) ;; => {:result true, :num-tests 100, :seed 1382488326530} Scheme • При разработке Scheme упор был сделан на элегантность и простоту языка. • Философия языка подчёркнуто минималистская. • Его цель — не сваливать в кучу разные полезные конструкции и средства, а напротив — удалить слабости и ограничения, вызывающие необходимость добавления в язык новых возможностей. Scheme примеры • • • • • Предикаты: (number? 5) (number? "foo") (string? "foo") По соглашению все предикаты заканчиваются символом «?» Scheme • (equal? "foo" "bar") • (eqv? 5 (+ 2 3)) • (eq? 'a 'A) • Определение функции: (define имя_функции (lambda (список_аргументов) (реализация_функции))), • Или более коротко: (define (имя_функции аргументы) (реализация_функции)). Scheme • Ввод-вывод (write (+ (read) (read))) • ;; факториал в (неэффективном) рекурсивном стиле (define (fact x) (if (< x 3) x (* (fact (- x 1)) x))) Miranda • Чистый функциональный язык программирования. • Не содержит императивных конструкций любого вида. • Имеет строгую полиморфную систему типов, поддерживает типы данных пользователя. • Как и язык ML преподаётся во многих университетах Miranda • • • • • • • Пример простой программы: z = sq x / sq y sq n = n * n x=a+b y=a-b a = 10 b=5 Miranda • week_days = ["Mon","Tue","Wed","Thur","Fri"] • days = week_days ++ ["Sat","Sun"] /* • 0:[1,2,3] = [0,1,2,3] • #days = 7 • days!0 = "Mon". */ Miranda • fac n = product [1..n] • result = sum [1,3..100] Miranda • quadsolve a b c = error "complex roots", = [-b/(2*a)], = [-b/(2*a) + radix/(2*a), -b/(2*a) - radix/(2*a)], where delta = b*b - 4*a*c radix = sqrt delta if delta<0 if delta=0 if delta>0 Miranda • fib 0 = 0 • fib 1 = 1 • fib (n+2) = fib (n+1) + fib n • sum [] = 0 • sum (a:x) = a + sum x • product [] = 1 • product (a:x) = a * product x • reverse [] = [] • reverse (a:x) = reverse x ++ [a] Miranda • answer = twice twice twice suc 0 • twice f x = f (f x) • suc x = x + 1 • foldr op k [] = k • foldr op k (a:x) = op a (foldr op k x) • sum = foldr (+) 0 • product = foldr (*) 1 • reverse = foldr postfix [] where postfix a x = x ++ [a] Miranda • [ n*n | n <- [1..100] ] • factors n = [ i | i <- [1..n div 2]; n mod i = 0 ] • sort [] = [] • sort (a:x) = sort [ b | b <- x; b<=a ] ++ [a] ++ sort [ b | b <- x; b>a ] Miranda • ones = 1 : ones • nats = [0..] • odds = [1,3..] • squares = [ n*n | n <- [0..] ] • perfects = [ n | n <- [1..]; sum(factors n) = n ] • primes = sieve [ 2.. ] where sieve (p:x) = p : sieve [ n | n <- x; n mod p > 0 ] Haskell • Берёт начало из языка Miranda • Имеет интерпретаторы и компиляторы (HUGS, Glasgow Haskell Compiler (GHC)) • Интегрируется в программные системы: .Net – Mondrian, COM/ActiveX – HaskellScript, Java – jaskell • ООП: O’Haskell, Haskell++ и Mondrian Haskell • Считается одним из «чистых» функциональных языков, хотя и содержит, например, операции ввода-вывода при помощи монад. Считается, что опытный программист не будет ими злоупотреблять. • getLine = do c <- getChar if c == '\n' then return "" else do l <- getLine return (c:l) Erlang • Позволяет писать программы для разного рода распределённых систем. • Разработан и поддерживается компанией Ericsson. • Язык включает в себя средства порождения параллельных процессов и их коммуникации с помощью посылки асинхронных сообщений. • Программа транслируется в байт-код, исполняемый виртуальной машиной, что обеспечивает переносимость. • Кратко формулу языка можно выразить как Erlang=функциональный язык+процессы. • Синтаксис наследован от Prolog. Erlang • Отсутствие присваиваний позволяет Erlang избежать таких традиционных для императивных языков проблем распределённых приложений, как необходимость синхронизации, опасность возникновения тупиков и гонок. • Java – Everything is an object • Lisp – Everything is a list • Erlang – Everything is a process • Язык стимулирует к созданию большого количества конкурентных процессов. • Процессы жёстко изолированы и не имеют общего состояния. Erlang • Параллельные вычисления. • Надежность. Erlang позволяет выстраивать различные сценарии для отслеживания всевозможных состояний системы – от примитивных (отслеживание состояния различных процессов) до продвинутых (таких, как создание failoverкластеров). • «Горячая» замена кода. Erlang позволяет отслеживать изменения в системе и загружать обновленные версии кода без остановки всей системы, что особенно важно, если такая остановка невыгодна или невозможна. • Внешние интерфейсы. Процессы в Erlang-е взаимодействуют друг с другом путем передачи асинхроных сообщений. На этом же принципе построено взаимодействие и с программами, написанными на С/С++ или Java. Существует также интерфейс взаимодействия с .NET. Erlang • Стандартные библиотеки: • Mnesia. Распределенная СУБД. • Inets. HTTP-клиент и сервер, а также FTPклиент. • Orber. CORBA v2.0 Object Request Broker (ORB). Erlang • Для телекоммуникационного оборудования (например, в компаниях Ericsson и Nortel). • Для создания сервера ejabberd на основе протокола Jabber. • Для управления поездами (например, в метро в городе Лион, Франция). • В БД-приложениях, нуждающихся в режиме, близком к режиму реального времени. Erlang • • • • • -module(tut1). -export([fac/1, mult/2]). fac(1) -> 1; fac(N) -> N * fac(N - 1). mult(X, Y) -> X * Y. • list_length([]) -> 0; • list_length([First | Rest]) -> 1 + list_length(Rest). Erlang • -module(tut14). • -export([start/0, say_something/2]). • say_something(What, 0) -> • done; • say_something(What, Times) -> • io:format("~p~n", [What]), • say_something(What, Times - 1). • start() -> • spawn(tut14, say_something, [hello, 3]), • spawn(tut14, say_something, [goodbye, 3]). tut14:start(). hello goodbye <0.63.0> hello goodbye hello goodbye Erlang 1> [2*N || N <- [1,2,3,4]]. [2,4,6,8] 2> [X || X <- [1,2,3,4,5,6,7,8,9,10], X rem 2 =:= 0]. [2,4,6,8,10] Erlang tail recursion duplicate(0,_) -> []; duplicate(N,Term) when N > 0 -> [Term|duplicate(N-1,Term)]. tail_duplicate(N,Term) -> tail_duplicate(N,Term,[]). tail_duplicate(0,_,List) -> List; tail_duplicate(N,Term,List) when N > 0 -> tail_duplicate(N-1, Term, [Term|List]). -module(ch3). -behaviour(gen_server). -export([start_link/0]). -export([alloc/0, free/1]). -export([init/1, handle_call/3, handle_cast/2]). start_link() -> gen_server:start_link({local, ch3}, ch3, [], []). alloc() -> gen_server:call(ch3, alloc). free(Ch) -> gen_server:cast(ch3, {free, Ch}). init(_Args) -> {ok, channels()}. handle_call(alloc, _From, Chs) -> {Ch, Chs2} = alloc(Chs), {reply, Ch, Chs2}. handle_cast({free, Ch}, Chs) -> Chs2 = free(Ch, Chs), {noreply, Chs2}. OTP And much more! At learnyousomeerlang.com ML • Функциональный язык общего назначения, разработанный в конце 1970 Робертом Милнером в Университете Эдинбурга • Имеет также императивные элементы • Имеет множество диалектов, наиболее известные из которых на данный момент: Standart ML, OCaml и F# ML • fun fact n = let fun fac 0 = 1 | fac n = n * fac (n - 1) in if (n < 0) then raise Fail "negative argument" else fac n end ML • Caml – – • • • • • • • Objective Caml, известный диалект Caml c поддержкой ООП Moscow ML – популярная реализация Standard ML произошедшая от Caml light Standard ML Alice F# Rpal LML (Lazy ML) Mythryl Nemerle VAL • Ориентированный на значения алгоритмический язык • Был разработан для потоковых архитектур Деннисом в 1979 году • Базируется на математической модели «схемы Денниса» • Имеет особую обработку ошибок • Присутствуют итерации • Отсутствуют рекурсия и ввод/вывод Sisal • Streams and Iteration in a Single Assignment Language • Функциональный язык однократного присваивания с неявным параллелизмом, ориентированный на научные вычисления • Разрабатывался университетом Манцестера, LLNL, университетом Колорадо and DEC • Sisal 1.3 по проведённым тестам в 1986 был сравним в производительности с Си. Sisal • define main • type OneDim = array [ real ]; • type TwoDim = array [ OneDim ]; • function generate( n : integer • returns TwoDim, TwoDim ) • for i in 1, n cross j in 1, n • returns array of real(i)/real(j) • array of real(i)*real(j) • end for • end function % generate Sisal • for i in 1, number_of_values new_val := deep_thought( value[i] ) returns array of new_val unless new_val > upper_val | new_val < lower_val end for Sisal • Особые циклические конструкции • Наличие массивов • Модель всюду завершаемых частичных вычислений • «многословный» синтаксис • Ориентированность на научные вычисления