реферат по Haskell. ПРИZS-341 Исаков Д.С. реферат по haskell. Функциональный язык программирования Haskell
Скачать 33.95 Kb.
|
ФГБОУ ВО «Ростовский Государственный Экономический Университет (РИНХ)» Кафедра Информационных систем и прикладной информатики Реферат На тему: «Функциональный язык программирования Haskell» По дисциплине: Функциональное и логическое программирование Выполнил: Студент группы ПРИZS-341 Исаков Д.С. Ростов-на-Дону 2019 Содержание Введение 3 Описание языка, основные команды и функции 4 Статическая система типов 4 Логический вывод типов 4 Чистота функциональности 5 Параллельность 6 Конкретное применение и примеры 8 Возьмём простой пример всем известной программы Hello world. 8 Стоит отметить, что в данной программе, написанной на Haskell, обязательной является только последняя строка. Первые две строки могут быть опущены. Следующий пример - вычисление факториала несколькими способами: 8 Сортировка Quicksort на Haskell 9 Заключение 10 Список источников 11 ВведениеЯзык программирования Haskell, названный в честь Хаскелля Брукса Карри, чьи работы в области математической логики служат основой функциональных языков - это стандартизированный, чистый функциональный язык программирования общего назначения, довольно отличающийся от остальных языков программирования, также часто называемый “ленивым” языком программирования. Haskell основан на лямбда-исчислении, поэтому лямбда используется как логотип. Язык специально разработан, чтобы оперировать широким спектром функций, от численных до символических. Поэтому Haskell имеет ясный синтаксис и богатое разнообразие встроенных типов данных, включая длинные целые и рациональные числа, а также обычные целые числа, числа с плавающей запятой и булевые типы. Описание языка, основные команды и функцииСтатическая система типовКаждое выражение в Haskell имеет тип, который устанавливается во время компиляции. Приложение должно сопоставить все типы. Если они не совпадают, то компилятор не выполнит программу. Типы являются не только формой гарантии, но и языком выражения конструкции программы. Все переменные в Haskell имеют тип: char = 'a' :: Char int = 123 :: Int fun = isDigit :: Char -> Bool Если не передать функции переменные правильных типов, компилятор отвергнет программу: Type error isDigit 1 Есть возможность декодировать байты в текст: bytes = Crypto.Hash.SHA1.hash "hello" :: ByteString text = decodeUtf8 bytes :: Text Но нельзя декодировать текст, который уже является последовательностью символов Unicode: Type error doubleDecode = decodeUtf8 (decodeUtf8 bytes) Логический вывод типов Не обязательно явно назначать тип каждой переменной в Haskell. Типы будут назначены двунаправленной унификацией типов. Однако можно обозначить типы, которые мы выбираем, или попросить компилятор обозначить их за нас для легкодоступной документации. В данном примере для каждой связи есть сигнатура типа: main :: IO () main = do line :: String <- getLine print (parseDigit line) where parseDigit :: String -> Maybe Int parseDigit ((c :: Char) : _) = if isDigit c then Just (ord c - ord '0') else Nothing Но можно просто написать следующее: main = do line <- getLine print (parseDigit line) where parseDigit (c : _) = if isDigit c then Just (ord c - ord '0') else Nothing Также можно использовать вывод типов во избежание траты времени, объясняя, чего мы хотим: do ss <- decode "[\"Hello!\",\"World!\"]" is <- decode "[1,2,3]" return (zipWith (\s i -> s ++ " " ++ show (i + 5)) ss is) => Just ["Hello! 6","World! 7"] Типы независимо определяют спецификацию синтаксического анализатора. То есть ввод данного типа не приемлем: do ss <- decode "[1,2,3]" is <- decode "[null,null,null]" return (zipWith (\s i -> s ++ " " ++ show (i + 5)) ss is) => Nothing Функции не вычисляют свои аргументы. Это значит, что программа может довольно хорошо сформироваться, с возможностью писать проверяющие конструкции (н-р if/else), просто составляя нормальные функции. Чистота кода Haskell облегчает соединение цепочек из функций, предоставляя преимущество в производительности. Определить проверяющие конструкции можно следующим образом: when p m = if p then m else return () main = do args <- getArgs when (null args) (putStrLn "No args specified!") Чистота функциональностиКаждая функция в Haskell - это функция в математическом смысле (т.е. "чистая"). Даже операции ввода/вывода, влекущие за собой некоторые побочные эффекты и являющиеся только описанием действия, написаны на чистом коде. Здесь нет утверждений и инструкций, только выражения, которые не могут видоизмениться в переменные (локальные или глобальные) и которые не имеют доступ к структурам таким как время или случайные числа. Следующая функция принимает целое число и возвращает целое число. Из-за типа она не может произвести побочного эффекта во что бы то ни было, она не может изменить ни один из своих аргументов. square :: Int -> Int square x = x * x Следующее соединение строк будет произведено успешно: "Hello: " ++ "World!" Однако следующий пример выдаст ошибку типов: Type error "Name: " ++ getLine так как getLine имеет тип IO String, а не String как "Name: ". Поэтому из-за системы типов вы не можете смешивать и соотносить чистое и нечистое. Параллельность Haskell хорошо сочетается с параллельным программированием из-за явной обработки эффектов. В его ведущем компиляторе, GHC, присутствует высоко производительный параллельный сборщик мусора и легковесная библиотека распараллеливания, содержащая полезные примитивы распараллеливания и абстракции. Потоки легко устанавливаются и связываются со стандартной библиотекой: main = do done <- newEmptyMVar forkIO (do putStrLn "I'm one thread!" putMVar done "Done!") second <- forkIO (do delayThread 100000 putStrLn "I'm another thread!") killThread second msg <- takeMVar done putStrLn msg Использование асинхронного API для потоков: do a1 <- async (getURL url1) a2 <- async (getURL url2) page1 <- wait a1 page2 <- wait a2 ... Атомарные потоки с программной транзакционной памятью: transfer :: Account -> Account -> Int -> IO () transfer from to amount = atomically (do deposit to amount withdraw from amount) Атомарные транзакции должны быть повторяющимися, поэтому независимый ввод/вывод запрещен в системе типов: Type error main = atomically (putStrLn "Hello!") Конкретное применение и примерыВозьмём простой пример всем известной программы Hello world.module Main where main :: IO () main = putStrLn "Hello, World!" Стоит отметить, что в данной программе, написанной на Haskell, обязательной является только последняя строка. Первые две строки могут быть опущены. Следующий пример - вычисление факториала несколькими способами: -- Пояснение типов (не обязательно) factorial :: (Integral a) => a -> a -- С использованием рекурсии factorial n | n < 2 = 1 factorial n = n * factorial (n - 1) -- С использованием рекурсии с ограничением factorial n | n < 2 = 1 | otherwise = n * factorial (n - 1) -- С использованием рекурсии, но без отождествления Using recursion but written without pattern matching factorial n = if n > 0 then n * factorial (n-1) else 1 -- С использованием списков factorial n = product [1..n] -- С использованием fold (встроенное) factorial n = foldl (*) 1 [1..n] -- Point-free factorial = foldr (*) 1 . enumFromTo 1 Сортировка Quicksort на Haskellquicksort :: Ord a => [a] -> [a] quicksort [] = [] quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater) where lesser = filter (< p) xs greater = filter (>= p) xs ЗаключениеНа сегодняшний день главной отличительностью Haskell от других функциональных языков программирования является то, что в нём используется чистая функциональная парадигма. Сами же создатели языка утверждают, что на Haskell проще писать сложные программы, и программы получаются существенно короче; программы имеют ясный, легко читаемый вид; их можно легко понять, даже не зная многих деталей языка Haskell; делается меньше ошибок, так как синтаксис языка Haskell защищает программиста от совершения многих типичных ошибок; короче и проще этап проектирования и разработки программ: программист должен просто понять, что ему нужно, и затем описать это на формальном математическом языке; создаются адаптивные, легко изменяемые и расширяемые программы. Кроме того, отмечается, что благодаря строгой типизации языка, в программах на Haskell не случается системных ошибок и не бывает аварийных ситуаций (сore dump). Создатели также утверждают, что программы на Haskell получаются более модульными и встраиваемыми и предоставляют больше возможностей для повторного использования (англ. codereuse). В частности, представленная программа быстрой сортировки на Haskell (в отличие от программы на Си) может сортировать не только целые числа, но и числа типа FLOAT и любые другие объекты, на которых определена операция сравнения. Язык Haskel имеет высокий уровень абстракции. Под этим имеется в виду возможность создавать функции, которые возвращают функции. Если точнее - Haskell включает в себя абстрактное лямбда-исчисление (λ-исчисление). Мощь, которую предоставляет это исчисление, ещё не до конца осознана программистами, и не в полной мере используется на практике. Сегодня важно иметь средства для разработки действительно сложных систем, где важно, чтобы программисты не увязали в собственном коде и были способны понять текст программ, который был написан месяц или год назад. Именно поэтому многие разработчики языков программирования в качестве одного из важных достоинств языка указывают его близость к естественному языку (обычно английскому). Список источниковАнтон Холомьёв – Учебник по Haskell (2012) Пол Хьюдак, Джон Хью, Пэйтон Джонс Саймон; Филип Фадлер - История Haskell: будь ленивым с классом (2007) Вики Учебник - Язык Haskell: О пользе и вреде лени Денис Москвин. Системы типизации лямбда-исчисления (2013) А. Филд, П. Харрисон - Функциональное программирование (1993). |