• Как рекурсивно распарсить скобки?

    @art_of_press
    Вы, почему-то, не используете одну из самых мощных фич Хаскелла - типы. Программа гораздо легче пишется, когда вы её сначала написали на уровне типов. Функции после этого пишутся гораздо легче.

    Переходя к вашей задаче: я бы разделил её на два этапа.

    1. Лексический разбор строки на список токенов.

    2. Парсинг списка токенов в выражение.

    Какие у вас могут быть токены? Числа, операторы, левая и правая скобки. Вот их и кодируйте в типе Token:

    data Token = NumToken Double | OpToken Operator | LeftParenToken | RightParenToken
    
    data Operator = Plus | Minus | Mult | Div


    В типе Token конструктору данных NumToken я передал Double, т.к. если у вас будет деление, с Int или Integer вы не сможете его произвести без дополнительной конвертации.

    Дальше вы должны превратить вашу строку в список токенов. Это отлично делается рекурсией:

    strToToken :: String -> [Token]
    strToToken [] = []
    strToToken (c:cs)
        -- Токенизируем голову списка и вызываем токенизацию на его хвосте
        | c == '(' = LeftParenToken : strToToken cs
        | c == ')' = RightParenToken : strToToken cs
        -- Если встречается пробел - откидываем его и токенизируем строку дальше
        | isSpace c = strToToken cs
        -- если встречается число, вызываем функцию-хелпер number
        | isDigit c = number c cs
        -- не забываем о случаях, когда строку не удалось распарсить полностью
        | otherwise = error $ "Не могу распарсить " ++ [c]


    Функция strToToken и вспомогательная функция number являются взаимно рекурсивными. Из функции strToToken мы вызываем функцию number, а из функции number мы вызываем функцию strToToken:

    number :: Char -> String -> [Token]
    number c cs =
        -- разбиваем строку на цифровые символы, идущие друг за другом, 
        -- и на остаток строки при помощи функции span
        let (digits,rest) = span isDigit cs
        -- сразу переводим полученные цифровые символы в число 
        -- при помощи функции read и токенизируем остаток строки
        in NumToken (read $ c:digits) : strToToken rest


    Вот вы и сконвертировали строку в список лексем. Следующая задача - парсинг лексем в выражения. Советую точно так же создать тип, содержащий все возможные выражения. Подсказка: этот тип у вас получится рекурсивным, т.к. выражение может состоять из нескольких выражений, разделённых операторами.
    Ответ написан
    2 комментария
  • Копируется ли состояние при каждой операции над монадой состояния в Haskell?

    @nirvimel
    Несмотря на то, что State внутри тоже стек, надо разделить саму State и структуру данных, которая через него протаскивается:
    from collections import namedtuple
    
    State = namedtuple('State', ('fx', 'previous'))
    State.unit = staticmethod(lambda value=None: State(lambda: value, None))
    State.bind = lambda self, fx: State(fx, self)
    State.get = lambda self: self.fx(self.previous.get()) if self.previous else self.fx()
    
    push = lambda value: lambda stack: (value, stack) if stack else value
    pop = lambda stack: stack[1] if isinstance(stack, tuple) else stack
    toList = lambda stack: toList(stack[1]) + [stack[0]] if isinstance(stack, tuple) else [stack]
    
    print (State.unit()
           .bind(push(1))
           .bind(push(2))
           .bind(push(3))
           .bind(pop)
           .bind(toList)
           .get()) # [1, 2]


    toList - довольно медленная, приведена только для примера.
    Ответ написан
    Комментировать
  • Копируется ли состояние при каждой операции над монадой состояния в Haskell?

    Копируется, только надо учитывать ленивость и чистоту Хаскеля.
    Если взять обычный список и класть ему в голову - ничего не надо будет копировать, так как добавление головы не требует копирования хвоста, новый список будет просто ссылаться на хвост. Удаление головы (т.е. взятие хвоста) тоже не требует создавать копий.
    Если же вы будете в качестве состояния использовать какой-либо строгий тип данных, да с unboxed членами, тот да, будет копироваться.
    Надо учитывать так же и другую вещь: накопление thunk'ов. Например, если состояние - это число, и вы миллион раз сделаете modify (+1), по факту там будет лежать отложенное вычисление на миллион прибавлений единиц, что будет кушать память. Потому есть строгая монада state, а также modify', который форсирует применение переданной функции.
    Ответ написан
    Комментировать
  • Какой курс этичного хакинга выбрать?

    27cm
    @27cm
    TODO: Написать статус
    github.com/s4n7h0/xvwa — специально плохо написанное приложение на PHP/MySQL для изучения аспектов безопасности.
    Ответ написан
    Комментировать
  • Как раскрасить notepad?

    @nirvimel
    D' Normalization расписал все правильно, только в действительности все несколько сложнее. Функции создания окна (меню и все элементы управления - тоже окна; windows же) нигде не принимают цвет через параметр. По умолчанию окна отрисовываются в цветах системной "темы". Чтобы переопределить цвета, надо перехватывать WndProc соответствующего окна, в нем на событие WM_PAINT устанавливать цвет Pen и Brush, пересылать сообщение оригинальному обработчику и надеяться на то что он сам не переопределяет Pen и Brush на каждый вызов WM_PAINT.
    Придется дописывать много кода, компилировать его так что-бы в нем или совсем не было абсолютных адресов (относительные short jumps) или все абсолютные адреса точно попадали в ту область, в которую предполагается вставка. Тут уже без ассемблера не обойтись (сколько же на Тостере за последнее время вопросов: "Где ассемблер незаменим?").
    Далее идет внедрение кода, как у вирусов. На эту тему можно много литературы найти. Если коротко, то есть два варианта: 1) дописать свой код в "хвост" секции кода, если поместится; 2) создать еще одну секцию кода в конце файла, это вариант открывает больше возможностей, но большинство антивирусов будут ругаться на такой exe-шник.
    Потом найти точку для патча, вырезать оттуда часть кода (например, вызов api-функции с подготовкой аргументов), перенести в свой код, а в той точке пропатчить что-то типа call our_code_block \ nop \ nop \ nop ....
    В общем задачка очень серьезная и с наскока такое не решается.
    Ответ написан
    1 комментарий
  • Как бы Вы изменили структуру программы в Python основываясь на ООП?

    @deliro
    Структура вашей программы совсем не понятна, поэтому нельзя точно сказать, куда пихать ООП.

    ModifyValueN можно заменить на что-нибудь такое:
    def modify(value, func):
        return func(value)

    И использовать как-нибудь так:
    x1 = modify(x1, lambda x: x**2) # Не сложно догадаться, что это возведение в квадрат.


    P.S. Почитайте PEP8, умоляю
    Ответ написан
    5 комментариев
  • Хорошие книги по Computer Science?

    vt4a2h
    @vt4a2h
    Senior software engineer (C++/Qt/boost)
    Советую пользоваться гуглом и поиском по сайту. Обсуждали уже 100500 раз.
    Ответ написан
    Комментировать
  • Хорошие книги по Computer Science?

    dimonchik2013
    @dimonchik2013
    non progredi est regredi
    Ответ написан
    Комментировать
  • Можно ли использовать скрипты в проекте C#?

    NightmareZ
    @NightmareZ
    Разработчик
    Ответ написан
    Комментировать
  • Можно ли использовать скрипты в проекте C#?

    saboteur_kiev
    @saboteur_kiev Куратор тега Программирование
    software engineer
    Неудачно ник себе выбрали. Даже как-то объяснять не хочется.
    Ответ написан
    1 комментарий
  • Регулярное выражение для разделения слова с цифрой. Из "Привет1234" нужно получить 2 совпадения Привет и 1234. Знает кто как?

    Gorily
    @Gorily
    Тестировать лучше тут: regexstorm.net/tester, у вас же C#?
    Для решения нужно просто найти стыки вида "не цифра-цифра", регулярка простейшая:
    ([\D])([\d])
    Затем делаем замену на:
    $1 $2
    И получаем искомый пробел.
    b74421bd9ee34fd6bddb9e10a47b5559.png
    Ответ написан
    1 комментарий
  • Чему обучать Junior'a?

    saboteur_kiev
    @saboteur_kiev
    software engineer
    1. Выделяете джуниору куратора, даете джуниору не слишком сложные задания.

    2. Куратору вменить в обязанность помогать (отвечать на вопросы, ориентировать в правильном направлении, но не делать вместо). Джуниора тоже поставить в извесность, что вопросы и неясности - сразу к куратору.

    3 Минимум раз в день, по возможности 2-3 раза в день, куратор должен сам проверять что наделал пациент и если тот лезет не туда, направить верным путем.
    Ответ написан
    3 комментария
  • Сойдет ли Scala как второй язык после JS?

    @nirvimel
    Scala более похож на js из всех языков

    Это что шутка такая? Как статический, компилируемый язык со строгой типизацией и развитой системой типов может быть похож на динамический интерпретируемый скрипт?
    Ответ написан
    1 комментарий
  • Какие есть аналоги Visual Studio для убунту?

    Olej
    @Olej
    инженер, программист, преподаватель
    IDE
    Разработка программных проектов в Linux (инструме...
    понравилась вижуал студио

    Kdevelop, Eclipse IDE, Solaris Studio, IntelliJ IDEA, Code::Blocks IDE, Geany, Glade, Anjuta, QDevelop, HaiQ, ... - каждый со своей ориентацией, и это ещё не всё, и каждый не хуже "вижуал студии".

    Но!!!
    В UNIX/Linux совсем другая философия, сам Linux - это уже IDE, и для небольших проектов здесь вообще не нужно ничего кроме текстового редактора с цветовой разметкой, здесь навороченные IDE не нужны, не пользуются популярностью, используются только для очень крупных групповых проектов.
    Возьмите Geany, как комфортный редактор кодов для 40 языков программирования - и будет вас счастье!
    Ответ написан
    1 комментарий
  • В чем смысл PostCSS сегодня?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    В последнее время началась мода на PostCSS - много постов, статей о нем.

    А почему бы и да? Любые инструменты надо пиарить что бы народ ими пользовался. Ибо народ будет пользоваться тем что на слуху (ну или тем с чем привык работать). Больше народа - больше идей, быстрее идет развитие, формируется комьюнити и поддерживать решение становится чуть проще. Да и приятно это когда твои наработки используют.

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

    Где ж это вы такое прочитали? postcss был попыткой решить проблемы, которые нельзя решить препроцессорами (или можно но долго).

    Окей, будем считать так, тем паче, что история коммитов на Гите это скорее подтверждает.

    Что именно подтверждает? сначала был Sass написанный рубистами что бы CSS можно было бы готовить так же нежно как они готовят HTML на HAML (кофескрипт туда же, рубистам хотелось сделать js похожим на ruby). И это заметте было в 2006-ом году! тогда и js был медленный, и V8 может только в планах был...

    Ведь все, что умеет PostCSS, умеют и препроцессоры

    postcss из коробки не умеет ровным счетом ничего. Он может только загрузить AST CSS файла и слепить из него обратно тот же CSS.

    И именно в этом сила postcss - модульность. Все существующие препроцессоры монолитны. То есть вы не можете просто так взять и добавить что-то свое туда. Да, в последних версиях less (и вроде как sass туда же подтягивается) у вас есть примитивный набор средств что бы вклиниться в процесс обработки AST документа и добавить какие-то примитивные вещи. Но это не удобно. Если вы хотите динамически менять проперти (например пересчитывать rem в em) или добавлять еще (опять же для того что бы руками не плодить в css кастыли для разных браузеров и делать это автоматом, на завязываясь ни на миксины и оставляя CSS чистым) свойств, но сделать это на less/sass сложно.

    Намного проще взять postcss и натравить это дело на результат работы препроцессоров.

    Давайте придумаем пример того, что можно легко и просто сделать при помощи пост процессоров и что сложно сделать с препроцессорами. Самое первое что приходит в голову - инлайнинг ресурсов. Например мелкие png-ки. Или работа с относительными путями, ресолвинг оных точнее. В этом случае мы с postcss напишем маленькую функцию, которая пробежится по всему абстрактному синтаксическому дереву и найдет использование url(). далее мы можем проверить размеры картинки и заинлайнить их (если у них размер достаточно маленький). Или собрать список всех задействованных картинок и использовать их потом (например что бы скопировать только то, что мы реально используем).

    Вот как-то так. А за счет того что мы имеем доступ целиком и полностью к формированию и обработке AST мы можем и синтаксис CSS развивать. Примерами могут служить многочисленные плагины аля cssnext и т.п. Можно даже большую часть фич sass в виде плагинов подключить.

    А самое забавное, что работает это все быстрее того же libsass на плюсах. За счет архитектуры (имею в виду не голый postcss а с набором плагинов добавляющих функциональность sass).
    Ответ написан
    Комментировать
  • Ваше понимание полиморфизма?

    magalex
    @magalex
    Архитектор распределённых систем управления
    Это механизм, позволяющий обращаться по одному и тому же имени к разным сущностям.

    На примере функций (полиформизм по параметрам):
    int max( int, int );
    double max( double, double);

    На примере классов (полиформизм по типам):
    class Animal{}
    class Dog : public Animal {}
    class Cat : public Animal {}
    Animal* animal1 = new Dog();
    Animal* animal2 = new Cat();
    Ответ написан
    Комментировать
  • Что по советуете подростку в программировании?

    opium
    @opium
    Просто люблю качественно работать
    если посмотреть глобально совершенно не вижу особой разницы между всеми языками, циклы условия
    ну есть местами фишечки типо ооп или там какой нибудь хитрой лябда функции , но в целом то все довольно одинаково
    Ответ написан
    Комментировать
  • Какой ФП язык выучить?

    @benoni
    программер-любтель, иногда подрабатываю фрилансом
    Еще есть:
    - Nemerle (тоже дот.нет, как и упоминавшийся F#, но инфы про немерле мало),
    - Rust (набирающий известность от мозилы, есть вроде даже книженция на руссом),
    - hy (лисп для питона, пока он больше экспериментальный),
    - Elm (хаскелеподобный язык, компилируется в JS),
    - Common Lisp (классический лисп, так сказать),
    - Scheme (больше учебный диалект лиспа, хотя есть Racket (диалект Scheme), который вроде кем-то даже для продакшена применяется),
    - Prolog (наиболее известный язык логического программирования).

    А так плюсы минусы наиболее популярных:
    - Erlang (ПЛЮСЫ: один из наиболее легких в изучении ФП языков, применяется в продакшене в сфере телекоммуникаций, а также в последнее время в вебе, в основном чаты и т.п.; МИНУСЫ: не является языком общего назначения, специфический прологовский синтаксис).
    - Clojure (ПЛЮСЫ: довольно легкий в изучении, JVM-платформа, ClojureScript (диалект кложуры для компиляции в джаваскрипт), есть порт на .NET-платформу, лисп; МИНУСЫ: JVM-платформа, другие реализации менее развиты, лисповые скобочки на любителя).
    - F# (ПЛЮСЫ: поддерживается майкрософтом и заточен под .NET, МИНУСЫ: ограниченность .NET-ом).
    - Scala (ПЛЮСЫ: набирает популярность, может через время очень потеснить джаву, доступна и ООП и ФП парадигмы, мощный, МИНУСЫ: сложный для новичнов в ФП).
    - Haskell (ПЛЮСЫ: очень мощный, практически универскальный, многие фишки современного программирования пришли из хаскеля, МИНУСЫ: довольно сложный для новичков, как и скала).

    P.S. я бы выбирал из кложуры, эрланга и хаскеля.
    P.P.S. если интересно в целом для себя можно ограничится Scheme и изучением SICPа.
    Ответ написан
    3 комментария
  • Как заменить, используя sed?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    #! /bin/sed -nf
    
    1{p;h;}
    2~1{H;x;s/\n.//;p;}
    x
    s/^\(.\).*$/\1/
    h

    А теперь попробуй понять, как это работает.
    Ответ написан
    3 комментария