LINUX.ORG.RU

[функциональщина тред][вопрос к специалистам] что выбрать?


0

1

На работе занимаюсь обработкой текстов на естественном языке.

Собственно, пока задачи были маленькие и понятные (типа морфологии и т.п.), в качестве основного языка программирования использовался С++, который был выбран был по ряду причин: работает быстро, есть необходимые абстракции, ничего особого хитрого в задачах нет, заказчики нормально воспринимают код и могут его оценить.

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

А раз так, задумался я над тем какой язык выбрать для реализации. Собрав задницу в кулак и мозг в голову, я прошерстил интернет на предмет того каким решением можно воспользоваться в данной области, по результатам были отобраны следующие языки: Prolog, OCaml, Lisp, Scheme, Haskell и, как это ни странно, Python и Erlang.

Маленькое уточнение: требуется кроссплатформенное решение (windows, linux, macos) с возможностью компиляции в байт-код, хорошо бы иметь потоки, GUI не особо нужны, но будут плюсом, ide - неважно. Ещё один важный момент: наличие коммерческих реализаций с целью дальнейшего на них перехода или, как вариант, серьёзного бэкграунда.

Понятно, что на любом из этих языков можно реализовать всё что угодно, посему оценивались больше практические моменты использования, так вот, поковырявшись с вышеперечисленными языками я сделал для себя следующие выводы о готовности их к использованию в production:

  • Prolog - собственно существуют довольно вменяемые открытые и коммерческие реализации, однако общее состояние дел большее напоминает заброшенную ферму (например, разные реализации интерпретатора могут использовать разный синтаксис).
  • OCaml - неплохой претендент, немного стагнирует в своём развитии, но имеет существенную поддержку в лице INRIA (и небольшой буст со стороны в виде F#).
  • Lisp - весьма разносторонний язык, есть весьма вменяемая свободная реализация (Clozure CL; SBCL, увы, *nix oriented) и мега-буст с точки зрения коммерческих реализаций (Allegro CL, LispWorks), есть так же реализация под Java VM.
  • Scheme - сводный брат Lisp, ситуация обстоит приблизительно так же, хотя непонятно что с коммерческими реализациями и вообще Scheme имеет репутацию академического языка.
  • Haskell - довольно молодая и таки тёмная лошадка, есть некоторый зоопарк в реализациях, коммерческие средства отсутствуют, присутствует некоторый перекос ориентации в сторону *nix.
  • Python - довольно годный язык, но поддержка функциональной парадигмы там реализована довольно слабо + наличествуют всякие выкрутасы (типа GIL).
  • Erlang - годный Prolog-like язык, но меня смущает его ориентация на телеком.

Как то вот так у меня получилось (большого опыта работы с данными языками у меня нет, так что, если я где в оценке промахнулся, просьба тыкнуть меня носом :)).

Сам пока склоняюсь к Lisp.

Собственно, товарищи опытные функциональщики, нужен Ваш совет относительно данной ситуации, что бы использовали Вы (что использовали Вы), что будет более/менее годное для решения подобного класса задач, какие есть подводные камни. И, самое главное, какие по Вашему мнению языки вляются более перспективными, на какие в первую очередь стоит тратить своё время.

Уф! Дописал. Всем откликнувшимся большое спасибо заранее. :)

ЗЫ brainf*ck и иже с ним не предлагать.

★★★★★

Ответ на: комментарий от archimag

Как ты собираешься расширять пролог, что бы он стал способен работать на уровне логики второго порядка?

Я не знаю как именно - я упомянул возможность которая доказана (солверы для такой логики писались). Это нужно конкретно смотреть как именно построить такую систему.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

> я упомянул возможность которая доказана

Доказана возможность расширения дизайна пролога для использования с логикой второго порядка???

солверы для такой логики писались


Вообще говоря, даже не все высказывания логики первого порядка могут быть всегда доказаны за приемлемое время (при крупной базе фактов). А с логиками более высоких порядков дело намного хуже.

archimag ★★★
()
Ответ на: комментарий от archimag

Доказана возможность расширения дизайна пролога для использования с логикой второго порядка???

Минимальный пролог очень простой - его выражения эта фактическая математическая запись, поэтому введение высказывания над предикатом мало что изменит:

(<- (relation1 object1 object2))
(<- (relation2 object1 object2))
(<- (meta-relation relation1 relation2))

Вообще говоря, даже не все высказывания логики первого порядка могут быть всегда доказаны за приемлемое время (при крупной базе фактов). А с логиками более высоких порядков дело намного хуже.

Ну наверно поэтому такие системы существуют пока только в математически ориентированном ПО. Тем не менее существуют способы которые обеспечивают приемлемую производительность таких солвером (как раз в используется в таком мат. ПО).

quasimoto ★★★★
()
Ответ на: комментарий от shty

>а под linux ccl как себя показал?

Под Линакс я его не пробовал, ибо там SBCL

Под виндой так и сижу на ccl - иногда погрызаю кактус, но на виндовый SBCL всё переходить не тороплюсь.

anonymous
()
Ответ на: комментарий от linuxfan

> Попробуй составить hashmap из строки вида {key_len:KEYvalue_len:value}*.

hashmap я строить не умею, а от строки-то что нужно?

разбить на записи (ограниченные {}) с полями key_len, KEYvalue_len, value?

korvin_ ★★★★★
()
Ответ на: комментарий от korvin_

{}* подразумевают повторение записей. Никаких лишних «{}» в строке нет. Число:строка, где число — длина следующей за ней строки.

linuxfan
()
Ответ на: комментарий от shty

> а под винду есть вообще вменяемые реализации CL, исключая коммерческие?

ECL. Умеет инкрементную сборку используя vs/gcc в зависимоти от ОС. В отсутствии компилятра умеет байт-код. Треды есть. Привязка к qt собственого изготовления. Может быть встроенным в виде библиотеки.

antares0 ★★★★
()
Ответ на: комментарий от linuxfan
(defun foo (string)
  (let ((hash-table (make-hash-table :test #'equal)))
    (dolist (e (split "," string))
      (register-groups-bind (length value)
          ("\\s*(\\d+)\\s*:\\s*(\\S+)\\s*" e)
        (when (and length value)
          (setf (gethash value hash-table) (parse-integer length)))))
    hash-table))
quasimoto ★★★★
()
Ответ на: комментарий от korvin_

> Попробуй составить hashmap из строки вида

{key_len:KEYvalue_len:value}*.


Хм, а какое это имеет отношение к работе со строками я не очень понял, фигли там работать то?

(defun parse-hashmap (str &aux (curpos 0))
  (flet ((parse-value ()             
           (multiple-value-bind (len pos) (parse-integer str :start curpos :junk-allowed t)
             (setf curpos (+ (incf pos) len))
             (subseq str pos curpos))))
    (loop while (< curpos (length str))
       collect (cons (parse-value)
                     (parse-value)))))
archimag ★★★
()
Ответ на: комментарий от antares0

Под виндой с этим самым ECL полнейший сракотан.

VS обсирается на крупных файлах. (например, ecl с vs++2008 не смог собрать cl-unicode, в последний раз когда я это пробовал делать).

Под mingw у последних ECL вообще какие-то фундаментальные проблемы со сборкой(например, просит getuid и, естественно, не находит; устанавливает директорию сборки не в build, а в корневую директорию сорцов, и т.п. Не исключаю, что mingw/msys рантайм у меня глючный, однако же все остальное, что должно под ним собираться - собирается).

Это не считая, что код, им скомпилированный, дичайше тормозит.

Единственный его плюс - встраиваемость. Соответственно, ECL, по-моему, стоит использовать только когда оное действительно необходимо.

Love5an
()
Ответ на: комментарий от archimag

Я написал

"5 : dsf , 6 : df , 62 : fgfgjdxs" => (hash-table string number)

number это не длинна string, т.к. такая хэш таблица для данной строки - бессмысленность.

С cl-ppcre можно легко добавить сахару - пробелы между разделителями разрешить, переносы строки.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Блин, ну посмотри ещё раз на условие:

key_len:KEYvalue_len:value

Т.е. сначала длина ключа, потом двоеточие и сам ключ, потом длина значения, двоеточие и значение, и т.п. Регулярные выражение здесь не нужны и особо ничем помочь не могут.

archimag ★★★
()
Ответ на: комментарий от archimag

Значит немного не понял - но не суть. Как раз регэкспы тут и помогут :) - я подправлю шаблон и всё станет на свои места.

Регулярные выражение здесь не нужны и особо ничем помочь не могут.

Да не, на регекспах проще делать такие вещи (wiki-parser разве не на них?), их легко расширить - вместо того чтобы переписывать код парсера.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

> Как раз регэкспы тут и помогут :) - я подправлю шаблон и всё станет

на свои места.


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

archimag ★★★
()
Ответ на: комментарий от archimag

Блин, я не вижу тут проблемы :) Я говорю - смысла задачи я не понял (к чему этот пример), но любая вариация - это незначительное изменение как кода с рег. выражением, так и вручную сделанного парсера (как у тебя). При попытки как-то расширить синтаксис (пробельные разделители, комментарии, разделители разного вида) регулярные выражения, конечно, выигрывают у вручную сделанного парсера - есть разные примеры таких парсеров на регулярных выражениях. Разве что в разборе сложных грамматик использовать их становится не комильфо (но всё равно можно) - на это есть разнее lalr или peg парсеры.

З.Ы. о чём мы тут спорим, вообще ? :)

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

linuxfan сказал, что в CL ужасная работа со стоками и при этом в следующем посту специально уточнил, что речь идёт не об регулярных выражениях, а об полностью ручной работе со строками. И для подтверждения своей точки зрения привёл пример формата, который видимо вызвал у него проблемы при разборе на CL.

archimag ★★★
()
Ответ на: комментарий от archimag

Наверно речь шла про

(concatenate 'string "abc" "dfg")
vs
"abc" . "dfg"

(subseq "abc" 2)
vs
"abc"[2]

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

quasimoto ★★★★
()
Ответ на: комментарий от archimag

>Хм, а какое это имеет отношение к работе со строками я не очень понял, фигли там работать то?

Хм, вроде и правда не так уж страшно. Но в свое время мне что-то не понравилось.

linuxfan
()
Ответ на: комментарий от quasimoto

>Да не, на регекспах проще делать такие вещи

И вот такие «таланты» понахерачат регэкспов там, где можно было тупо в лоб попарсить, а потом сидят и удивляются: хер ли так медленно работает?

linuxfan
()
Ответ на: комментарий от archimag

>И для подтверждения своей точки зрения привёл пример формата, который видимо вызвал у него проблемы при разборе на CL.

Ну не то чтобы проблематично, просто в C такая штука весьма элегантно делается абсолютно без копирований вставкой нулевых байт по нужному месту.

И да, похоже, неприязнь у меня вызывала именно «многословная» конкатенация.

linuxfan
()
Ответ на: комментарий от linuxfan

И вот такие «таланты» понахерачат регэкспов там, где можно было тупо в лоб попарсить, а потом сидят и удивляются: хер ли так медленно работает?

В лоб парсить - это всегда последнее дело. Лучше поднимать теорию и практику эффективной трансляции разных парсерных дсл (в т.ч. регэкспов).

О каких талантах идёт речь - и почему в кавычках? Кстати : http://lionet.livejournal.com/68807.html

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

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

quasimoto ★★★★
()
Ответ на: комментарий от linuxfan

> {}* подразумевают повторение записей. Никаких лишних «{}» в строке нет. Число:строка, где число — длина следующей за ней строки.

гм... ну архимаг уже показал, но в случае возможности я бы просто преобразил данные в s-expr (т.е. если нет необходимости периодически работать с такими данными, а просто нужно «старые данные» распарсить и дальше работать с подобным (семантически, не синтаксически) форматом)

ну у тебя там скорее «терм:терм:терм» (key_len:KEYvalue_len:value) или в этом и смысл, что первое (или второе) двоеточие не считается? и ещё эти разные регистры... в общем, как бы это не звучало, но формат текстового представления бестолковый... =)

korvin_ ★★★★★
()
Ответ на: комментарий от quasimoto

>В лоб парсить - это всегда последнее дело.

Последнее дело — это пихать куда ни попадя любимые технологии, в том числе и регэкспы. Хотя если пишешь «для себя» на любимом языке, можно как угодно поступать.

О каких талантах идёт речь - и почему в кавычках?

Речь идет о людях с талантом превращать все в матан (в плохом смысле этого слова).

Кстати : http://lionet.livejournal.com/68807.html

У тебя хватит наивности утверждать, что любую задачу разбора текста нужно решать регулярными выражениями, потому что, якобы, есть библиотека «быстрых регэкспов»?

linuxfan
()
Ответ на: комментарий от dmsh

Ты не понял. Узким местом будет сам пролог

Узким местом будет программист, написавший обмолотку данных вейвлетами на прологе.

mv ★★★★★
()
Ответ на: комментарий от linuxfan

Последнее дело — это пихать куда ни попадя любимые технологии, в том числе и регэкспы.

У тебя хватит наивности утверждать, что любую задачу разбора текста нужно решать регулярными выражениями, потому что, якобы, есть библиотека «быстрых регэкспов»?

Дело не в «любимых технологиях», тут речь немного о другом - скажем выражение «qwe:5:rty» можно распарсить и вручную, точно так же как можно распарсить вручную URL, с другой стороны сложные грамматики нужно парсить подходящими инструментами (lalr или peg - я их выше уже упомянул, кстати). А вот многие прикладные задачи разбора несложных грамматик вполне можно делать с помощью регулярных выражений. Т.е. речь о том что у нас есть ряд задач и ряд инструментов для их решения - вот мы и выбираем нужный.

Ок, я виноват - не заметил что ты хотел без cl-ppcre. Но всё таки, возьмём пример - немного расширим задачу, пусть будет такой синтаксис:

 abc : 5 :: qwe ;
 def : 6 :: rty ;
 ...

Да, я видел ручной код на си строк этак на 500 который парсит подобные выражения, но это не очень весело. Если уж говорит об удобном выборе инструмента, то представив это как

code ::= {line ;}*
line ::= tok : num : tok

Я беру регекспы и покрываю первый класс продукций одним split и второй с помощью какого-нибудь register-group-bind. Короче - пишу свои пять строк которые решают задачу, и ещё одну строку для чтения из файла. При этом даже могу рассчитывать на какую-то эффективность (линейную от входа или квадратичную, если не очень заморачиваться). Вот поэтому и говорю, что для многих задач регулярные выражения вполне подходят. А что взамен? Писать те самые 500 строк на си?

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

quasimoto, ты слишком абстрагируешься от конкретной задачи, а это не есть хорошо. linuxfan попросить разобрать конкретный пример формата, для которого регулярные выражения бесполезны, а ты игнорируешь этот факт и продолжаешь раздувать абстракциями. Остановись.

archimag ★★★
()
Ответ на: комментарий от quasimoto

>А что взамен? Писать те самые 500 строк на си?

Сильно зависит от того, что ты делаешь. Если одноразовая говноподелка на коленке, то можешь хоть свою декларативную библиотеку для регэкспов на прологе изобретать, применяя ее затем в CL. А если тебе надо распарсить пару гигабайт таких данных, то сядешь как миленький за C.

P. S. где там 500 строк-то?

linuxfan
()
Ответ на: комментарий от linuxfan

Надеюсь до соревнований по парсингу 2 гб не дойдёт?) А то вот например вспомнилось: http://13-49-ru.blogspot.com/2010/06/repl.html

P. S. где там 500 строк-то?

Это условное впечатление, но много там было - while на пробелы скушать, if на типы разделителей, внешний while, сообщения всякие.

quasimoto ★★★★
()
Ответ на: комментарий от linuxfan

декларативную библиотеку для регэкспов на прологе изобретать
декларативную
регэкспов
прологе

Это ещё зачем ?

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

>Надеюсь до соревнований по парсингу 2 гб не дойдёт?)

На C это очень быстро, кстати. Я парсил и 3-4 гигабайтные логи. И суточного онанизма с REPL'ами не требовалось. Кстати, когда-то давно пробегала новость о тулзе, которая может сохранять и восстанавливать состояние линуксовых приложений. Для простенького парсера логов сработает наверняка.

Это условное впечатление, но много там было - while на пробелы скушать, if на типы разделителей, внешний while, сообщения всякие.

Позволь полюбопытствовать, а в лисповом коде сообщения по умолчанию не пишутся?

linuxfan
()
Ответ на: комментарий от linuxfan

Чтобы было круто и функционально. На производительность-то нам наплевать, как я понял.

А приведи цитату где я говорил что плевать на производительность? Основной упор как раз на то что сейчас такие удобные средства как регулярные выражения могут быть использованы без боязни за плохую производительность - там умные алгоритмы используются (они строят конечный автомат по регулярному выражению с линейной сложностью).

Позволь полюбопытствовать, а в лисповом коде сообщения по умолчанию не пишутся?

Ну так сообщения будут писаться парсером (он уже есть) - от пользователя требуется только сформулировать правила для него, в случае регулярок - всего два варианта соответствует шаблону/или нет (писать почти нечего). Ну ведь в любом случае - несколько строк vs. сколько там строк вручную написанного парсера - соотношение LOC очевидно же.

На C это очень быстро, кстати. Я парсил и 3-4 гигабайтные логи.

Моя тоже парсил. Сколь примерно пришлось писать на си кода?

Если серьёзно - нужно будет обдумать это дело и попробовать устроить бенчмарк. Я ставлю на то что в обоих случаях будет O(N), но коэффицент у си кода будет лучше - где-то 80-90%.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

А вообще для логов есть grep. Но так как repl - рулит и педалит... :)

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

>Основной упор как раз на то что сейчас такие удобные средства как регулярные выражения могут быть использованы без боязни за плохую производительность - там умные алгоритмы используются (они строят конечный автомат по регулярному выражению с линейной сложностью).

Wanna test it? Кстати, ты забыл упомянуть, что быстро работают только правильно написанные регулярные выражения, но об этом обычно и правда не думают, но свято верят, что a=(.*);.*b=(.*);.*c=(.*) будет работать хорошо.

в случае регулярок - всего два варианта соответствует шаблону/или нет

Класс! «У вас какая-то херня написана» — замечательное диагностическое сообщение. Я, кстати, напоминаю, что регулярные выражения подходят далеко не для всего, к чему их пытаются приспособить (например, к «разбору» HTML).

Моя тоже парсил. Сколь примерно пришлось писать на си кода?

В сумме 150 строк. Из них меньше 80 на разбор строки лога, остальное на анализ и вывод. Анализ, правда, на C++ был.

linuxfan
()
Ответ на: комментарий от quasimoto

>Я ставлю на то что в обоих случаях будет O(N)

Меня всегда умиляли подобные утверждения. Что есть N в данном случае? Число строк в файле? Среднее число символов в строке? Объем входных данных в байтах?

linuxfan
()
Ответ на: комментарий от linuxfan

Я, кстати, напоминаю, что регулярные выражения подходят далеко не для всего, к чему их пытаются приспособить (например, к «разбору» HTML).

Ну так и я о чём - прикладные задачки, по сути утилитарное назначение (навроде распарсить список вида {имя фамилия = оклад}* или скажем {опкод аргумент [аргумент]}*). Строго говоря - для автоматных грамматик, HTML вообще говоря контекстно-свободная грамматика (т.к. допускает по крайней мере неограниченные вложения).

Класс! «У вас какая-то херня написана» — замечательное диагностическое сообщение.

Не так, а «выражение `иван петров = 100g00' не соответствует шаблону `имя фамилия = цифрь'».

А как переписать a=(.*);.*b=(.*);.*c=(.*) чтобы оно не быо жадным?

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

>А как переписать a=(.*);.*b=(.*);.*c=(.*) чтобы оно не быо жадным?

Ну, чуть лучше (и правильней) будет a=([^;]*).*;b=([^;]*).*;c=([^;]*). Но вообще говоря, только регэкспами эта задача решается плохо. Разумней всего разбить строку на подстроки по ';' и анализировать их по отдельности. Что-то вроде

echo 'a=2;b=3;d=8;c=5' | sed -re 's/;/\n/g' | sed -nre 's/(a|b|c)[[:space:]]*=[[:space:]]*(.*)/\1 is \«\2\»/p'

linuxfan
()
Ответ на: комментарий от linuxfan

Ну так можно вообще провести унификацию:

let string = "a = 2 ; b = 3 ; d = 8 ; c = 5"
  map
    split "="
    split ";" string

или

some_combine
  split infix_1
  ..
  split infix_k
  string

и в общем O(n^k), k - количество инфиксных операторов. Короче `by definition, whether an operator is greedy cannot affect whether a regular expression matches a particular string as a whole; it only affects the choice of submatch boundaries' т.е. даже «жадные» матчеры могут быть сделаны в среднем как линейные (в теории :)).

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

>даже «жадные» матчеры могут быть сделаны в среднем как линейные (в теории :)).

Это какая-то неправильная теория, так как очевидно, что жадный оператор должен проверять возможность сопоставления строки с оставшейся частью образца несколько раз (в идеале один раз, но тут все зависит от входной стороки).

linuxfan
()
Ответ на: комментарий от quasimoto

>там умные алгоритмы используются (они строят конечный автомат по регулярному выражению с линейной сложностью).

CL-PPCRE, насколько я понимаю, это все же PCRE. А в перловские регексы - нерегулярные. Запросто может быть экспоненциальное время разбора.
http://lionet.livejournal.com/68807.html

Love5an
()
Ответ на: комментарий от Love5an

CL-PPCRE, насколько я понимаю, это все же PCRE.

Есть ещё http://common-lisp.net/projects/cl-irregsexp/, хотя там Boyer-Moore matchers (в cl-ppcre он же, но упрощённый вариант - он выглядит несколько лучше.

http://lionet.livejournal.com/68807.html

Я про такие регулярные выражения и говорю.

quasimoto ★★★★
()
Ответ на: комментарий от linuxfan

На C это очень быстро, кстати. Я парсил и 3-4 гигабайтные логи. И суточного онанизма с REPL'ами не требовалось. Кстати, когда-то давно пробегала новость о тулзе, которая может сохранять и восстанавливать состояние линуксовых приложений. Для простенького парсера логов сработает наверняка.

Суточный онанизм с REPL'ом проигрывал данные с биржи за весь день программой на DSL'е, которую я за несколько минут написал, чтобы подтвердить гипотезу. На Си её аналог пришлось бы писать гораздо дольше, чем то время, за которое ответ на вопрос нашёлся.

mv ★★★★★
()
Ответ на: комментарий от mv

Ты не поверишь, но анализатор логов начинался с дикой комбинации grep + sed, но стало очевидно, что summary этими средствами не посчитать, да и обработка суточного лога занимала десятки минут.

Я не против прототипирования, я против неоправданной неэффективности.

BTW сильно кастрированный аналог REPL'а для нативного кода называется gdb.

linuxfan
()
Ответ на: комментарий от linuxfan

В упомянутом блоге в статье приводится сложность - O(n*m), где - n это вход, а m «ширина» выражения (или вес) короче говоря это можно назвать степенью жадности данного алгоритма (сопоставленного выражению) - в любом случае среднестатистическая сложность O(N*m) т.е. линейная.

quasimoto ★★★★
()
Ответ на: комментарий от linuxfan

BTW сильно кастрированный аналог REPL'а для нативного кода называется gdb.

Это считай репл для полу-ассемблера/полу-машинных кодов :) Как ближайший аналог нужен хотя бы репл для си (хотя, есть и такой велосипед).

quasimoto ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.