пятница, 15 марта 2013 г.

Подсветка синтаксиса haskell на blogspot

Однажды я согрешил. Честолюбие сыграло во мне, жадность и святая злость вскипели полным ходом. Тысячу раз приходя на сайт восхитительной книги Learn You A Haskell мне захотелось стырить замечательную подсветку синтаксиса Haskell вместе с элементами дизайна. Покопался в исходниках сайта, накачал css и js файлов, потом порылся в google на эту тему и задача решилась. На blogspot это заработало, хотя и с гораздо большим количеством костылей и элементов культа карго, чем это желательно.

Так как всем абсолютно безразлично на идеи, методы, высокий смысл, лучше я опишу итог. Все заработало достаточно удовлетворительно при моддинге простого шаблона, динамические шаблоны так и не "захотели" работать без вырвиглазной кривизны. В шаблоне сайта на blogger после тэга title я поместил следующие строки:

<link href='http://patamushta-ff.narod2.ru/styleHs.css' rel='stylesheet' type='text/css'/>
<link href='http://patamushta-ff.narod2.ru/SyntaxHighlighter.css' rel='stylesheet' type='text/css'/>
<script src='http://patamushta-ff.narod2.ru/shCore.js' type='text/javascript'/>
<script src='http://patamushta-ff.narod2.ru/shBrushPlain.js' type='text/javascript'/>
<script src='http://patamushta-ff.narod2.ru/shBrushHaskell.js' type='text/javascript'/>

При этом текст в редакторе блоггера должен быть обрамлен в два div'a:

<div class="bgwrapper">
<div id="content"<

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

<script type="text/javascript" src="http://patamushta-ff.narod2.ru/shAdd.js"></script>

После данных телесных манипуляций открылись новые кармические уровни для блоггинга в этом вашем blogspot. Первое, и самое главное, если к блоку pre, в который мы обычно помещаем листинг добавить атрибуты <pre name="code" class="haskell: ghci">, то будет получаться моднейший блок кода на хаскеле, абсолютно подсвеченный крутейшими цветами:

bmiTell :: (RealFloat a) => a -> a -> String  
bmiTell weight height  
    | bmi <= skinny = "You're underweight, you emo, you!"  
    | bmi <= normal = "You're supposedly normal. Pffft, I bet you're ugly!"  
    | bmi <= fat    = "You're fat! Lose some weight, fatty!"  
    | otherwise     = "You're a whale, congratulations!"  
    where bmi = weight / height ^ 2  
          skinny = 18.5  
          normal = 25.0  
          fat = 30.0  

И вторая фича. Текст в тэге <span class="fixed">foo</span> становится foo.

И последнее. Да, согласен, все это - дикий костыль и вообще невозможно использовать. Но мне это помогло.

четверг, 7 марта 2013 г.

MathJax в blogspot

Мы все постоянно хотим одного. Мы хотим красивых математических формул в браузере. Да еще чтобы набирать их можно было как в LaTeX'e. Осуществить эту мечту поможет замечательная штука MathJax, но при попытке подключить ее к blogspot можно испытать много боли. Google и небольшое знание английского языка помогли найти решение.

Сначала нужно подключить скрипт MathJax к посту. Для этого в одну строчку пишем (удалите лишние переводы строки!):

<script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

Затем пишем что-то в духе:

Если \(a \ne 0\), тогда существует два решения уравнения \(ax^2 + bx + c = 0\), которые можно представить в виде $$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$

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

Если \(a \ne 0\), то существуют два решения уравнения \(ax^2 + bx + c = 0\), которые представляются в виде $$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$

Eще пример:

\begin{pmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{pmatrix} становится симпатичной матрицей:

\begin{pmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{pmatrix}

Всем добра!

Простые бинарные деревья на Haskell


1. Бинарные деревья - очень крутая штука, применяющаяся просто везде: для представления множеств, поиска и т.д. Его полезность в том, что количество операций для поиска элемента пропорционально логарифму количества всех элементов. Все элементы с ключами, большими текущего элемента, находятся в правой ветви, а меньшие - в левой. Рассмотрим простые несбалансированные деревья. Определяется дерево очень просто: дерево либо пусто, либо содержит элемент некоторого типа и из него растут еще два дерева - левое и правое поддерево. Такое рекурсивное определение как нельзя лучше подходит для реализации на нашем любимом Haskell.

data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)

2. Теперь создадим функцию, которая добавляет элемент в дерево. Она должна делать так:

  • Если дерево пусто, то мы создаем вместо него синглетон, т.е. дерево с элементом и двумя пустыми поддеревьями.
  • Если не пусто, то если элемент меньше текущего, мы добавляем его в левое поддерево, если больше, то в правое. Если элемент совпадает, нужно оставить все как есть.
Как всегда, алгоритм на Haskell реализуется легкой формализацией словесного описания:
singleton :: a -> Tree a  
singleton x = Node x EmptyTree EmptyTree  
  
treeInsert :: (Ord a) => a -> Tree a -> Tree a  
treeInsert x EmptyTree = singleton x  
treeInsert x (Node a left right)   
    | x == a = Node x left right  
    | x < a  = Node a (treeInsert x left) right  
    | x > a  = Node a left (treeInsert x right)  

3. Поиск элемента в дереве тоже более чем прост благодаря его упорядоченной организации:

  • Если дерево пусто, то, очевидно, в нем нет искомого элемента
  • Если не пусто, то либо мы нашли, что искали, либо если искомое меньше текущего, то ищем в левом поддереве, иначе - в правом.
treeElem :: (Ord a) => a -> Tree a -> Bool
treeElem x EmptyTree = False
treeElem x (Node a left right) 
    | x == a = True
    | x < a  = treeElem x left
    | x > a  = treeElem x right  

4. Преобразование списка в дерево. Можно просто добавить список к пустому дереву, а перед этим реализовать функцию добавления к дереву списка объектов того же типа, что и в вершинах дерева.

makeTree :: Ord a => [a] -> Tree a
makeTree xs = treeListInsert xs EmptyTree

treeListInsert :: Ord a => [a] -> Tree a -> Tree a
treeListInsert [] tree = tree
treeListInsert (x:xs) tree = treeListInsert xs (treeInsert x tree)

5. Преобразование дерева в список также очевидно, причем список получается упорядоченным:

treeToList :: Ord a => Tree a -> [a]
treeToList EmptyTree = []
treeToList (Node a left right) = treeToList left ++ [a] ++ treeToList                            С                                                               right

6. Осталось реализовать: delete element; проверка балансировки... кроме этого, нужно реализовать сбалансированные деревья. так же интересно это сделать параллельно с модулем на языке С