haskell-first-app/

Решил потратить время на изучение какого-нибудь функционального языка программирования. Их оказалось довольно много, но наиболее правильным (обсуждаемым, активно используемым, хорошо документированным, …) мне показался Haskell. Недавно вышло несколько книг на русском языке, посвященных этому языку (автор — Роман Душкин ), что также повлияло на мой выбор.

Откуда во мне проснулся интерес к функциональным языкам, я расскажу как-нибудь в другой раз. Пока достаточно будет сказать, что у функциональных языков есть несколько интересных свойств. Да и просто ознакомиться с парадигмой, альтернативной вездесущему ООП, по крайне мере не повредит.

Не могу сказать, что я полностью разобрался в Haskell, но первую программку сваять получилось. Решил ее выложить, чтобы похвастаться была опорная точка для дальнейшего изучения языка. Кстати, я припоминаю, что в институте нас пытались учить какому-то функциональному языку (надо же, пригодилось!), возможно это даже был Haskell. К сожалению, когда я поинтересовался «а кому нужно это ваше функциональное программирование?», был получен ответ «ну, математикам так проще писать программы», после чего интерес к предмету пропал. Не верьте тому, чему учат в институтах! 🙂

Теперь немного ссылок и справочной информации:

  • GHC — наиболее каноничный компилятор Haskell. В комплекте с GHC идет программа ghci, запускающая компилятор в интерактивном режиме. Она часто используется в различных мануалах и облегчает отладку;
  • Hugs — популярный интерпретатор Haskell. Я им (пока?) не пользовался, но говорят, штука хорошая;
  • Hackage — онлайн-каталог модулей (п акедж ей) для H askell. Все недостающие модули нужно искать на нем;
  • Hoogle — поиск модулей и функций. Есть поиск функций по сигнатурам, что может пригодиться;
  • Cabal — система управления пакетами Haskell. Что-то вроде Perl ‘овой утилиты cpan;
  • Haddoc — система комментирования, типа Doxygen и Javadoc;

Изучив немного мат части, я бросился устанавливать ghc, cabal и тд. Оказывается, так делать не надо. Существует готовый пакет программ The Haskell Platform , включающий в себя все необходимое — GHC, Cabal, Haddoc и самые полезные модули. Есть инсталлятор под Windows, порт под FreeBSD (pkg_add -r hs-haskell-platform), пакеты для MacOS и различных дистрибутивов Linux. Среды разработки в комплекте нет, но на ее роль вполне подойдет VIM или Geany ( см пункт 6 ). Еще есть плагин для Eclipse , haskell-mode для Emacs и даже специальная (только для Хаскеля) IDE под названием Leksah . Я остановился на Geany.

В Haskell Platform для работы с регулярными выражениями предлагается использовать модуль Text.Regex.Posix. Проблема в том, что в нем реализованы регулярные выражения Posix, а я всю жизнь работал с регулярными выражениями Perl. Хоть разница между ними и небольшая, но мне так и не удалось понять, как в регулярных выражениях Posix будет выглядеть аналог (abc)(?:def)(ghi) и возможно ли его вообще написать. Также утверждается , что Text.Regex.Posix работает медленно, так что я решил установить Text.Regex.PCRE.

Установка новых модулей происходит очень просто:

cabal install regex-pcre

Правда, под Windows предварительно следует установить библиотеку pcre , а также воспользоваться флагами —extra-lib-dirs и —extra-include-dirs, иначе модуль не установится. Но такие сложности возникли только с Text.Regex.PCRE. Описание пакета и его правильное название можно найти на Хакедже.

Вообще, мне интересно, что мешало использовать в Cabal и самом языке одинаковые обозначения модулей? Например, позже выяснилось, что Data.String.Utils входит в пакет MissingH. Никакой связи между модулями языка и пакетами!

Дополнение: О статической линковке PCRE можно прочитать в 4-м параграфе статьи Кроссплатформенное GUI приложение на Haskell . Об использовании этой библиотекой напрямую вы можете прочитать в заметке Работа с регулярными выражениями в C/C++ при помощи библиотеки libpcre .

После установки можно немного потестировать модуль в ghci:

> :m +Text.Regex.PCRE
> «aaa» =~ «a» :: Bool
True
> «aaa» =~ «(a)(a)» :: Bool
True
> «Привет!!!» =~ «(?:При)(вет)» :: Bool
True
> «Привет!!!» =~ «(?:При)(вет)» :: (String,String,String,[String])
(«»,»105510881080107410771090″,»!!!»,[«107410771090»])
> :q

Наконец, мы добрались до кода. Приведенная программа скачивает видео с RuTube (пополняю коллекцию видео-доунлоудеров ). Описание алгоритма было найдено на tradiz.org , от меня требовалось только закодить его.

— rutube-dl.hs v 0.1.0
— (c) Alexandr A Alexeev 2011 | http://remontka.com/
— based on http://goo.gl/Q1TMU

import Data . Char — toLower
import Data . String . Utils — replace
import Text . Printf — printf
import Text . Regex . PCRE
import Network . HTTP
import System

— начало программы
main = do
args <- getArgs — получили аргументы
parseArgs args — обрабатываем их

— проверяем количество аргументов и выводим usage;
parseArgs :: [ String ] -> IO ( )

— если число аргументов — два или больше:
parseArgs ( url:outFile:xs ) = do
let xmlUrl = urlToXmlUrl url
xmlData <- httpGet xmlUrl
let cmd = genCmd ( xmlToRtmpUrl xmlData ) outFile
if cmd == «» then do
putStrLn $ «Failed to parse url!»
exitWith $ ExitFailure 1
else do
putStrLn $ «cmd: » ++ cmd
exitCode <- system cmd
putStrLn $ «rtmpdump terminated, exit code = » ++
show exitCode

— если передано меньше двух аргументов
parseArgs _ = do
progName <- getProgName
putStrLn $ «Usage: » ++ progName ++ » <url> <outfile>»
exitWith $ ExitFailure 2

— скачиваем заданную страницу
httpGet :: String -> IO ( String )
httpGet «» = do
return «»
httpGet url = do
query <- simpleHTTP ( getRequest url )
body <- getResponseBody query
return body

— преборазуем rtmp-ссылку и имя выходного файла в команду
genCmd :: String -> String -> String
genCmd rtmpUrl outFile =
let regex = «(?i)^(rtmp://[^ » /]+/)([^ «» ]*?/)(mp4:[^ «» ]*)$»»
match = rtmpUrl =~ regex :: [ [ String ] ]
in case match of
[ [ _ rtmp app playPath ] ] ->
let live = if app == «»vod/»» then «» —live»» else «»»»
— кавычка — нормальная часть имени
outFile’ = replace «» «» «» «» \ «» «» outFile in
— на самом деле ничего не выводим

Похожая запись

EnglishRussianUkrainian