Обо мне

Моя фотография
Дикий Полярный Сов
Показаны сообщения с ярлыком FP. Показать все сообщения
Показаны сообщения с ярлыком FP. Показать все сообщения

четверг, 9 декабря 2010 г.

понедельник, 27 сентября 2010 г.

Я вернулся.

Не знаю, надолго ли, но вернулся, гыгы.

Написал на хаскеле интерпретатор конечных автоматов Мили, аналогичный используемому в институте "МИЭМ-89" (написанному на паскале). На все про все ушло около двух вечеров: один разбирался с парсерами и их комбинаторами и писал свой велосипед (хотя, наверное, стоило бы повтыкать в Parsec), а второй - писал собственно интерпретатор.

Устанавливаем SDL-ные биндинги поверх Haskell Platform for Windows

Наткнулся на такую ссылку: http://web.animal-machine.com/blog/2010/04/a-haskell-adventure-in-windows/

пятница, 25 июня 2010 г.

Няшный Haskell.

На днях нарыл книжку "Programming in Haskell", начал потихоньку разбираться. Пока что понимаю не так уж много, но работаю над собой. Налицо, кстати, явное сходство F# с сабжем - afaik, одни и те же люди приложили руку к созданию как того, так и другого.

А сейчас - про общую, хех, "няшность" брутального Хаскеля. Игру про няшного котика, написанную на Haskell, все видели? Ну а теперь вот второе наблюдение - интерпретатор Хаскеля называется "hugs". Вот сидит такой одинокий программист, захочется ему обнять кого-нибудь, открывает он консоль и пишет там "обнимашки" (ну, hugs пишет, имею ввиду). И запускается ему интерпретатор, и теплеет у него на душе, и с блаженной улыбкой он начинает работать.

понедельник, 19 апреля 2010 г.

F# - красивая конструкция

Сижу, пишу сервер. Есть у меня две функции, которые принимают данные разных типов (String и byte array) и отправляют их в поток - первая, соответственно, для отправки клиенту текста (заголовки всякие, прочая белиберда), вторая - для отправки изображений и прочей бинарщины.

И вот, благодаря паттерн матчингу, их можно объединить:

let sendToStream (str: NetworkStream) (bin: Object) =
    match bin with
        | :? string as strn ->
            str.Write(System.Text.Encoding.UTF8.GetBytes(strn), 0, strn.Length)
        | :? (byte[])  as bytarr ->
            str.Write(bytarr, 0, bytarr.Length)

Вот такая вот функция. Что радует - увеличившийся уровень абстракции - стоит появиться какому-нибудь новому типу, для которого нужен свой способ отправки - все, что нужно изменить - паттерн. Благодаря наличию Object на верхнем уровне мы можем совать какие угодно данные в функцию. Правда, тут стоит следить за наследованием - ведь проверка типов может не дойти до нашего "нового" типа. Поэтому наиболее частные типы следует размещать как можно раньше.

P.S. Кстати, в приведенном примере компилятор найдет изъян - не покрыты все паттерны. Дело лечится добавлением граничного случая | _ -> failwith "Invalid input" например.

пятница, 16 апреля 2010 г.

Erlang - шифр цезаря.

Рад вам представить результат двух вечеров мучений - *барабанная дробь* - шифр Цезаря (а точнее, аффинные преобразования его же имени) на эрланге.

О том, что из этого получилось - под катом.


суббота, 27 марта 2010 г.

F# Mono Bug, или Микрософт как всегда.

Наткнулся сегодня на интересный баг в F#.
До конца локализовать пока не удалось, но, кажется, что паттерн матчинг с 'a option неправильно работает.
Итак. Имеем код (да, это тот самый шифр цезаря :] ):


module Caesar

let alphabet = Array.ofSeq "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.,?!+=/"

let getIndex (arr: 'a[]) (elt: 'a) =
    let optIndex = arr |> Array.tryFindIndex( (=) elt )
    match optIndex with
    | Some(x) ->
        printfn "found %A" x
        x
    | None ->
        printfn "None"
        -1

let encodeLetter (shift: int) (letter: char) =
    let idx =
        letter
        |> getIndex alphabet
    printfn "%c - %d" letter idx
    alphabet.[
        ( idx + shift ) % (Array.length alphabet)
        ]


В винде все работает, как и предполагалось - написав в fsi, к примеру

#load "caesar.fs"
Caesar.encodeLetter 5 'a';;

Получим на экране

found 0
a - 0
val it : char = 'f'

То есть - getIndex отработал как надо, достал нам индекс, что, в свою очередь означает, что паттерн матчинг Some(x) сработал. Под моно же имеем следующую картину:

None
a - -1
val it : char = 'e'

То есть явно видно, что в том же самом коде тот же самый паттерн не сработал.

Бьюсь в истерике Очень интересный баг.


UPD: Однако, если вызывать getIndex напрямую - выводит все как полагается. Значит, беспорядки начинаются уже в encodeLetter - почему-то "теряется"... пока не пойму что.

UPD2: Причина, оказывается, крылась в генерализации функции (я явно указал 'a в качестве типа параметра). Как только поменял типы параметров в getIndex на char - заработало и под Mono. Подозреваю, тут что-то связано с выводом типов. Буду ковырять дальше.

UPD3: У Mono с выводом типов вообще как-то не очень ладится. Не могли сделать все как в дотнет.

вторник, 9 марта 2010 г.

Компилируем бинарники из лиспа - SBCL и clisp

Давно не писал, потому что пока что почти все вечера у меня заняты погружением в Коммон Лисп.

Пощупал Clojure, и она мне, в целом, понравилась, если бы не одно "но" - совершенно неочевидные внутренние механизмы джавы, благодаря которым я вообще не понимаю, что к чему, что это за classpath, зачем он нужен, почему его надо явно указывать и с какой стати мой простейший скрипт на две строчки тормозит полторы секунды перед выполнением. Конечно же, если вникнуть во внутреннее устройство джавки и научиться компилировать мои clojure-произведения в *.jar, все будет работать быстрее. Но это впереди, а пока что я решил закончить-таки Practical Common LISP.

И сегодня я расскажу, как компилировать бинарник в SBCL и clisp.

Итак, начнем с SBCL. Подготовив наш файл к запуску, а именно - написав функцию, которая будет запускаться первой (этакий int main() :] ), мы грузим sbcl-овский REPL и пишем там:

(load "our-file-name")

Получив в ответ "Т", мы, в принципе, готовы приступать к компиляции. Вводим в REPL:

(sb-ext:save-lisp-and-die "binary-file-name" :executable t :toplevel 'function-name)

По идее, функция #'save-lisp-and-die просто сохраняет состояние интерпретатора лиспа, если бы не... параметр :executable вместе с :toplevel. Они содержат явное указание - скомпилировать бинарник, при запуске которого выполнится функция function-name. В качестве дополнительного требования к function-name sbcl просит явно вызывать функцию (quit).

Итак, когда я попробовал указанные выше манипуляции впервые и получил результат, радости моей не было предела. До тех пор, пока я не взглянул на размер бинарника - а он оказался, ни много ни мало, 28 мегабайт. Ага, для простенького скрипта. Ну, это остается на совести создателей SBCL, тем более, думаю, вряд ли сейчас для кого-то проблема бинарники в 20+ мег. Впрочем, глубоко этот вопрос я не ковырял, скорее всего, можно и сократить объем файла.

Теперь перейдем к clisp:

(load "our-file-name")
(ext:saveinitmem "binary-file-name" :executable t :init-function 'function-name :quiet t)


Здесь видим, что :toplevel меняется на :init-function и, кроме того, добавляется параметр :quiet, который препятствует показу баннера clisp перед запуском вашей программы. Меня такие вещи бесят. Кому нравится - не указывайте :quiet вообще.

Добавлю, что ваша программа должна содержать вызов функции #'ext:exit, чтобы она нормально завершила работу (иначе после того, как ваша программа завершится, пользователю покажут clisp-овский REPL).

Бинарник таким образом получается всего 5,5 мег.