Примеры программ на haskell

Haskell — необычный язык с точки зрения тех, кто привык к JavaScript, С++, Python или любому другому императивному языку. Всё дело в том, что Haskell — функциональный язык. Мы уже рассказывали, чем отличаются функциональные языки от остальных, теперь посмотрим на них в деле.

Haskell — не совсем для обычных вещей, и стандартное приложение с красивым интерфейсом на нём сделать не получится. А вот сделать серверную часть, которая возьмёт на себя все сложные вычисления, или консольную программу, которая вызывается через командную строку, — вполне. Лучше всего Haskell справляется с точными вычислениями и расчётами, поэтому чем лучше вы будете знать математику — тем лучше для кода.

Синтаксис в Haskell

Самая простая программа на Haskell выглядит так:

// Комментарий
main = putStrLn «Hello World!»

Давайте разберём, как работает единственная строка в программе. Main — это как бы главная функция, которая возвращает какое-то значение. В нашем случае оно возвращает значение вывода на экран строки «Hello World!» . Компилятор знает, что putStrLn — функция вывода на экран, но если бы он этого не знал, нам нужно было бы написать так:

Фигня этот ваш Haskell!

main = putStrLn «Hello World!»

Теперь мы явно указали тип функции main — это ввод и вывод каких-то результатов (IO — input/output, ввод-вывод). Ещё в Haskell есть такие базовые типы данных:

  • Integer — целое число
  • Char — символ
  • Double — число с плавающей точкой или дробное число

А ещё есть специальные конструкции (), [] и ->, с помощью которых можно сделать свои типы данных на основе базовых, например, список или массив.

Математические операции в Haskell работают и выглядят как обычно: +, –, *, /.

Функции и их значения

Почти всё в Haskell делается через функции. Задача программиста — описать функцию таким образом, чтобы компилятор понял:

  • какие параметры могут прийти в функцию,
  • что с ними нужно сделать,
  • в каком виде нужно отдать результат.

Получается, что функции — это наборы правил, по которым обрабатываются данные. Например, если нам нужно найти факториал любого числа, то на Haskell это можно записать так:

// факториал — произведение чисел от единицы до этого числа. // к примеру, факториал трёх равен 1 * 2 * 3 fac :: Integer -> Integer fac 0 = 1 fac n | n > 0 = n * fac (n — 1)

Первая строка после комментариев говорит нам, что мы объявляем новую функцию (fac) ,и работать с типами данных (::) она будет так: на вход ей поступит целое число (Integer) и на выходе функция вернёт тоже целое число (-> Integer) .

Вторая строка отвечает за то, что если нужно посчитать факториал ноля, то это будет единица.

Последняя строка — самая сложная и интересная. Следите за математической мыслью: факториал любого числа n (fac n) , где n больше нуля (| n > 0) , равен произведению этого числа (n *) на факториал предыдущего числа (fac (n – 1)) .

Что это за язык программирования Haskell такой? Душкин объяснит

Если пока непонятно, что тут происходит, — почитайте про рекурсию, там мы подробно разобрали этот пример.

Записки программиста

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

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

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

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

  • GHC — наиболее каноничный компилятор Haskell. В комплекте с GHC идет программа ghci, запускающая компилятор в интерактивном режиме. Она часто используется в различных мануалах и облегчает отладку;
  • Hugs — популярный интерпретатор Haskell. Я им (пока?) не пользовался, но говорят, штука хорошая;
  • Hackage — онлайн-каталог модулей (пакеджей) для Haskell. Все недостающие модули нужно искать на нем;
  • 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://eax.me/
— 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 parseArgs args — обрабатываем их

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

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

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

— скачиваем заданную страницу
httpGet :: String -> IO ( String )
httpGet «» = do
return «»
httpGet url = do
query body 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
— на самом деле ничего не выводим, как sprintf в сях
printf ( «rtmpdump —rtmp » %s » —app » %s » —playpath » %s » »
++ » —swfUrl http://rutube.ru/player.swf —flv » %s » %s» )
rtmp app playPath outFile live
_ -> «»

— выдираем rtmp-ссылку из xml файла
xmlToRtmpUrl :: String -> String
xmlToRtmpUrl xml =
let regex = «(?i)»
match = xml =~ regex :: [ [ String ] ]
in case match of
[ ] -> «»
[ [ _, rtmpUrl ] ] -> rtmpUrl

— преобразование ссылки на видео в ссылку на xml
urlToXmlUrl :: String -> String
urlToXmlUrl url =
let regex = «(?i)^(?:http://)?rutube \ .ru/.*?[ \ ?
match = url =~ regex :: [ [ String ] ]
in case match of
[ ] -> «»
[ [ _, hash ] ] -> «http://bl.rutube.ru/» ++ map toLower hash ++ «.xml»

Программа использует утилиту rtmpdump. В Windows ее можно просто положить в один каталог с exe’шником. Объяснять код, как я понимаю, бессмысленно, ибо он снабжен комментариями и ничего сверхсложного не делает. Поскольку это моя первая программа на Хаскеле, писал я ее не с нуля. Сначала был написан скрипт на Perl, после чего этот скрипт переписывался на Хаскель. Код скрипта:

# rutube-dl.pl v 0.1.0
# (c) 2011 Alexandr A Alexeev | http://eax.me/
# based on http://goo.gl/Q1TMU

my $url = shift ;
my $outfile = shift ;

die «Usage: $0 n »
unless $url and $outfile ;

print «Downloading $url. n » ;
my $data = `wget -q $url -O -` ;
die «Error: wget returns $? n » if ( $? ) ;

$url = $1 ;
print «Video url: $url n » ;

# предположительно, вариант с использованием http устарел
# TODO — проверить на 10 000 случайных роликах
if ( $url !~ m #^(rtmp://[^’/]+/)([^’]*?/)(mp4:[^’]*)$#i) <
die «Failed to parse video url n » ;
}

my ( $rtmp , $app , $playpath ) = ( $1 , $2 , $3 ) ;
print «rtmp = $rtmp n app = $app n playpath = $playpath n » ;
$outfile =~ s/’/’/g ;

my $cmd = «rtmpdump —rtmp ‘$rtmp’ —app ‘$app’ —playpath ‘$playpath'» ;
$cmd .= » —swfUrl ‘http://rutube.ru/player.swf’ —flv ‘$outfile'» ;
$cmd .= » —live» if ( $app eq «vod/» ) ;

Вот, пожалуй, и все, о чем я хотел сегодня рассказать. В качестве дополнительных источников информации могу посоветовать хаскеловский сборник рецептов и онлайн-учебник LearnYouAHaskell.com. Если у вас совсем плохо с английским, обратите внимание на подборку русскоязычных материалов. Как обычно, любые вопросы и комментарии приветствуются.

Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.

Источник: eax.me

Haskell Language учебник
Начало работы с языком Haskell

Логотип Haskell

Haskell — это усовершенствованный чисто функциональный язык программирования.

Особенности:

  • Статически типизировано: каждое выражение в Haskell имеет тип, который определяется во время компиляции. Проверка статического типа — это процесс проверки безопасности типа программы на основе анализа текста программы (исходного кода). Если программа проходит проверку статического типа, то гарантируется, что программа удовлетворит некоторый набор свойств безопасности типа для всех возможных входов.
  • Чисто функциональный : каждая функция в Haskell является функцией в математическом смысле. Нет инструкций или инструкций, только выражений, которые не могут мутировать переменные (локальные или глобальные), а не состояния доступа, такие как временные или случайные числа.
  • Параллельно: его флагманский компилятор GHC поставляется с высокопроизводительным параллельным сборщиком мусора и небольшой библиотекой параллелизма, содержащим множество полезных примитивов параллелизма и абстракций.
  • Ленькая оценка: функции не оценивают свои аргументы. Задерживает оценку выражения до тех пор, пока не потребуется его значение.
  • Универсальный: Haskell построен для использования во всех контекстах и ​​средах.
  • Пакеты: вклад с открытым исходным кодом в Haskell очень активен с широким спектром пакетов, доступных на серверах общих пакетов.
Читайте также:
Программа обеспечения транспортной безопасности это

Последний стандарт Haskell — Haskell 2010. По состоянию на май 2016 года группа работает над следующей версией Haskell 2020.

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

Версии

Версия Дата выхода
Haskell 2010 2012-07-10
Haskell 98 2002-12-01

Привет, мир!

Базовый «Привет, мир!» программа в Haskell может быть выражена кратко только в одной или двух строках:

main :: IO () main = putStrLn «Hello, World!»

Первая строка представляет собой необязательную аннотацию типа, указывающую, что main является значением типа IO () , представляющим собой операцию ввода-вывода, которая «вычисляет» значение типа () (читает «единица», пустой кортеж не передает никакой информации) помимо выполнения некоторых побочных эффектов для внешнего мира (здесь, печатая строку на терминале). Аннотации этого типа обычно опущены для main потому что это его единственный возможный тип.

Поместите это в файл helloworld.hs и скомпилируйте его с помощью компилятора Haskell, такого как GHC:

ghc helloworld.hs

Выполнение скомпилированного файла приведет к выводу «Hello, World!» печатается на экране:

./helloworld Hello, World!

В качестве альтернативы runhaskell или runghc позволяют запускать программу в интерпретируемом режиме без необходимости ее компиляции:

runhaskell helloworld.hs

Интерактивный REPL также может использоваться вместо компиляции. Он поставляется с большинством сред Haskell, таких как ghci который поставляется вместе с компилятором GHC:

ghci> putStrLn «Hello World!» Hello, World! ghci>

Кроме того, загрузите скрипты в ghci из файла с помощью load (или :l ):

ghci> :load helloworld

:reload (или :r ) перезагружает все в ghci:

Prelude> :l helloworld.hs [1 of 1] Compiling Main ( helloworld.hs, interpreted ) *Main> :r Ok, modules loaded: Main.

Объяснение:

Эта первая строка является сигнатурой типа, объявляющей тип main :

main :: IO ()

Значения типа IO () описывают действия, которые могут взаимодействовать с внешним миром.

Поскольку Haskell имеет полноценную систему типа Hindley-Milner, которая позволяет автоматически вводить тип, титровые подписи технически необязательны: если вы просто опустите main :: IO () , компилятор сможет вывести тип самостоятельно анализируя определение main . Тем не менее, очень часто считается, что плохой стиль не записывать сигнатуры типов для определений верхнего уровня. Причины включают:

  • Типовые подписи в Haskell — очень полезная часть документации, потому что система типов настолько выразительна, что вы часто можете видеть, какая функция удобна для просто, глядя на ее тип. Эту «документацию» можно легко получить с помощью таких инструментов, как GHCi. И в отличие от обычной документации, контролер типа компилятора убедится, что он действительно соответствует определению функции!
  • Подписи типов сохраняют ошибки локально . Если вы допустили ошибку в определении без предоставления его сигнатуры типа, компилятор может не сразу сообщить об ошибке, а вместо этого просто вывести для него бессмысленный тип, с которым он фактически выглядит. При использовании этого значения вы можете получить критическое сообщение об ошибке. С подписью компилятор очень хорошо разбирается в ошибках, где они происходят.

Эта вторая строка выполняет фактическую работу:

main = putStrLn «Hello, World!»

Если вы исходите из императивного языка, может быть полезно отметить, что это определение также можно записать в виде:

main = do

Или, что то же самое, (Haskell имеет разводку на основе макета, но будьте осторожны, смешивая вкладки и пробелы непоследовательно, что будет путать этот механизм):

main = do putStrLn «Hello, World!» return ()

Каждая строка в блоке do представляет собой некоторое монадическое (здесь, I / O) вычисление , так что весь блок do представляет общее действие, состоящее из этих подэтапов, путем комбинирования их способом, определенным для данной монады (для ввода / вывода это означает просто выполнение их один за другим).

Синтаксис do сам по себе является синтаксическим сахаром для монад, например IO , и return — это действие no-op, создающее его аргумент без каких-либо побочных эффектов или дополнительных вычислений, которые могут быть частью определенного определения монады.

Вышеупомянутое то же самое, что и определение main = putStrLn «Hello, World!» , потому что значение putStrLn «Hello, World!» уже имеет тип IO () . Рассматривается как «заявление», putStrLn «Hello, World!» можно рассматривать как полную программу, и вы просто определяете main ссылку на эту программу.

putStrLn :: String -> IO () — thus, putStrLn (v :: String) :: IO ()

putStrLn — это функция, которая принимает строку в качестве аргумента и выводит действие ввода-вывода (то есть значение, представляющее программу, которую может выполнять среда выполнения). Время выполнения всегда выполняет действие с именем main , поэтому нам просто нужно определить его равным putStrLn «Hello, World!» ,

Факториал

Факториальная функция — Haskell «Hello World!» (и для функционального программирования в целом) в том смысле, что он лаконично демонстрирует основные принципы языка.

Вариант 1

fac :: (Integral a) => a -> a fac n = product [1..n]

  • Integral — это класс целочисленных типов чисел. Примеры включают Int и Integer .
  • (Integral a) => помещает ограничение на тип a находящийся в указанном классе
  • fac :: a -> a говорит, что fac — это функция, которая принимает a и возвращает a
  • product — это функция, которая накапливает все числа в списке, умножая их вместе.
  • [1..n] — это специальное обозначение, которое desugars для enumFromTo 1 n и является диапазоном чисел 1 ≤ x ≤ n .

Вариант 2

fac :: (Integral a) => a -> a fac 0 = 1 fac n = n * fac (n — 1)

Эта вариация использует сопоставление образцов, чтобы разбить определение функции на отдельные случаи. Первое определение вызывается, если аргумент равен 0 (иногда это называется условием останова), а второе определение — иначе (порядок определений значителен). Это также иллюстрирует рекурсию, поскольку fac ссылается на себя.

Стоит отметить, что из-за правил перезаписи обе версии fac будут скомпилированы с идентичным машинным кодом при использовании GHC с активированными оптимизациями. Таким образом, с точки зрения эффективности эти два будут эквивалентны.

Читайте также:
Юниверс отзывы о программе

Фибоначчи, используя ленивую оценку

Lazy оценка означает, что Haskell будет оценивать только элементы списка, значения которых необходимы.

Основным рекурсивным определением является:

Если оценивать напрямую, это будет очень медленно. Но, представьте, у нас есть список, который записывает все результаты,

fibs !! n
┌──────┐ ┌──────┐ ┌──────┐ │ f(0) │ │ f(1) │ │ f(2) │ fibs -> 0 : 1 : │ + │ : │ + │ : │ + │ : . │ f(1) │ │ f(2) │ │ f(3) │ └──────┘ └──────┘ └──────┘ ┌────────────────────────────────────────┐ │ f(0) : f(1) : f(2) : . │ └────────────────────────────────────────┘ -> 0 : 1 : + ┌────────────────────────────────────────┐ │ f(1) : f(2) : f(3) : . │ └────────────────────────────────────────┘

Это кодируется как:

fibn n = fibs !! n where fibs = 0 : 1 : map f [2..] f n = fibs !! (n-1) + fibs !! (n-2)
GHCi> let fibs = 0 : 1 : zipWith (+) fibs (tail fibs) GHCi> take 10 fibs [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

zipWith создает список, применяя данную двоичную функцию к соответствующим элементам из двух перечисленных ему списков, поэтому zipWith (+) [x1, x2, . ] [y1, y2, . ] равно [x1 + y1, x2 + y2, . ] .

Другой способ написания fibs это с scanl функции :

GHCi> let fibs = 0 : scanl (+) 1 fibs GHCi> take 10 fibs [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

scanl создает список частичных результатов, которые foldl бы foldl , работая слева направо по списку ввода. То есть scanl f z0 [x1, x2, . ] равно [z0, z1, z2, . ] where z1 = f z0 x1; z2 = f z1 x2; .

Благодаря ленивой оценке обе функции определяют бесконечные списки, не вычисляя их полностью. То есть, мы можем написать функцию fib , извлекая n-й элемент неограниченной последовательности Фибоначчи:

GHCi> let fib n = fibs !! n — (!!) being the list subscript operator — or in point-free style: GHCi> let fib = (fibs !!) GHCi> fib 9 34

Начиная

Онлайн REPL

Самый простой способ начать писать Haskell — это, вероятно, переход на веб-сайт Haskell или Try Haskell и использование онлайн-REPL (read-eval-print-loop) на главной странице. Онлайновый REPL поддерживает большинство базовых функций и даже некоторых IO.

Существует также базовый учебник доступен , который может быть запущен, набрав команду help . Идеальный инструмент, чтобы начать изучать основы Haskell и попробовать некоторые вещи.

GHC (я)

Для программистов, которые готовы заняться немного больше, есть GHCi , интерактивная среда, которая поставляется вместе с компилятором Glorious / Glasgow Haskell . GHC можно установить отдельно, но это только компилятор. Чтобы иметь возможность устанавливать новые библиотеки, необходимо также установить такие инструменты, как Cabal и Stack . Если вы используете Unix-подобную операционную систему, проще всего установить Stack, используя:

curl -sSL https://get.haskellstack.org/ | sh

Это устанавливает GHC, изолированный от остальной части вашей системы, поэтому его легко удалить. Однако всем командам должен предшествовать stack . Еще один простой подход — установить платформу Haskell . Платформа существует в двух вариантах:

  1. Минимальное распределение содержит только GHC (для компиляции) и Cabal / Stack (для установки и сборки пакетов)
  2. Полный дистрибутив дополнительно содержит инструменты для разработки проектов, профилирования и анализа охвата. Также включен дополнительный набор широко используемых пакетов.

Эти платформы можно установить, загрузив установщик и следуя инструкциям или используя диспетчер пакетов вашего дистрибутива (обратите внимание, что эта версия не гарантируется как актуальная):

    Ubuntu, Debian, Mint:

sudo apt-get install haskell-platform
sudo dnf install haskell-platform
sudo yum install haskell-platform
sudo pacman -S ghc cabal-install haskell-haddock-api haskell-haddock-library happy alex
sudo layman -a haskell sudo emerge haskell-platform
brew cask install haskell-platform

sudo port install haskell-platform

После установки должно быть возможно запустить GHCi , вызвав команду ghci любом месте терминала. Если установка прошла успешно, консоль должна выглядеть примерно так:

[email protected]:~$ ghci GHCi, version 6.12.1: http://www.haskell.org/ghc/ 😕 for help Prelude>

возможно, с дополнительной информацией о том, какие библиотеки были загружены перед Prelude> . Теперь консоль стала Haskell REPL, и вы можете выполнить код Haskell, как в онлайн-REPL. Чтобы выйти из этой интерактивной среды, можно ввести :q или :quit . Для получения дополнительной информации о том , что команды доступны в GHCi, типа 😕 как показано на начальном экране.

Поскольку писать одни и те же вещи снова и снова на одной строке не всегда так практически, может быть хорошей идеей написать код Haskell в файлах. Обычно эти файлы имеют .hs для расширения и могут быть загружены в REPL с помощью :l или :load .

Как упоминалось ранее, GHCi является частью GHC , который на самом деле является компилятором. Этот компилятор может быть использован для преобразования файла .hs с кодом Haskell в запущенную программу. Поскольку файл .hs может содержать множество функций, в файле должна быть определена main функция. Это будет отправной точкой для программы. Файл test.hs можно скомпилировать с помощью команды

ghc test.hs

это создаст объектные файлы и исполняемый файл, если ошибок не было, и main функция была определена правильно.

Дополнительные инструменты

  1. Это уже упоминалось ранее как диспетчер пакетов, но стек может быть полезным инструментом для разработки Haskell совершенно по-разному. После установки он способен
    • установка (несколько версий) GHC
    • создание проекта и строительные леса
    • управление зависимостями
    • проекты по строительству и тестированию
    • бенчмаркинг
    • IHaskell — это ядро haskell для IPython и позволяет комбинировать (runnable) код с уценкой и математической нотацией.

    Штрихи

    Несколько наиболее важных вариантов:

    Ниже 100

    import Data.List ( (\) ) ps100 = ((([2..100] \ [4,6..100]) \ [6,9..100]) \ [10,15..100]) \ [14,21..100] — = (((2:[3,5..100]) \ [9,15..100]) \ [25,35..100]) \ [49,63..100] — = (2:[3,5..100]) \ ([9,15..100] ++ [25,35..100] ++ [49,63..100])

    неограниченный

    Сито Эратосфена, использующее пакет данных :

    import qualified Data.List.Ordered ps = 2 : _Y ((3:) . minus [5,7..] . unionAll . map (p -> [p*p, p*p+2*p..])) _Y g = g (_Y g) — = g (g (_Y g)) = g (g (g (g (. )))) = g . g . g . g . .

    традиционный

    (субоптимальное пробное деление)

    ps = sieve [2..] where sieve (x:xs) = [x] ++ sieve [y | y 0] — = map head ( iterate ((x:xs) -> filter ((> 0).(`rem` x)) xs) [2..] )

    Оптимальное пробное деление

    ps = 2 : [n | n 0).rem n) $ takeWhile (( p*p > n || (rem n p > 0 r)) True ps]

    переходный

    От пробного деления до сита Эратосфена:

    [n | n

    Самый короткий код

    nubBy (((>1).).gcd) [2..] — i.e., nubBy (a b -> gcd a b > 1) [2..]

    nubBy также из Data.List , например (\) .

    Объявление значений

    Рейтинг
    ( Пока оценок нет )
    Загрузка ...
    EFT-Soft.ru