Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.12.13 06:14
Оценка: 17 (2)
Здравствуйте, alex_public, Вы писали:
_>Т.е. то, что я написал код вида
_>
_>for(;;){
_>    Analyze(rand());
_>    this_thread::sleep_for(chrono::seconds(1));
_>}
_>

Вы не написали такого кода. Вы написали совсем другой код, в котором никакого Analyze нету, и который построен на разрушающих изменениях локального состояния.

_>абсолютно никак не поменяло обсуждаемую функцию Analyzer.

Пока что никакой функции нету. Есть гипотетическая функция, которая конкурирует в обсуждении с конкретным, уже работающим кодом.

_>2. Если мы всё же говорим, что основной смысл Rx — это реализация паттерна Наблюдатель для коллекций, а не некие последующие linq-подобные извращения, то тогда у меня к Rx нет ни малейших претензий. Ну разве что кроме того, что обычно подобное проще написать самому, чем подключать стороннюю библиотеку.

Rx — это реализация паттерна "произвольные выражения" для цепочек событий.

_>Ну так если нам нужен конечный автомат, то для этого есть отличные специализированные инструменты, причём без всяких ужасов типа попытки записать некое подобие БНФ через linq синтаксис. Т.е. для простейших случаев пишем линейный код, а для сложных берём удобный конечный автомат (например boost.statechart). И это всё находится внутри функции Analyzer, которую опять же можно вызывать и внутри цикла и реактивным способом.

Нам не нужен конечный автомат. Точно так же, как нам не нужен стек для арифметики — удобнее просто писать арифметические выражения в школьной нотации.
Конечный (или бесконечный) автомат — это деталь реализации. А нам нужна возможность записать реакцию на события в понятном виде.
Ваш оппонент просто пытается вам объяснить, что с точки зрения декларативной семантики парсинг активно-читаемого текста и анализ цепочек событий — одно и то же, поэтому рулят системы, которые отделяют запись правил анализа от механизмов получения данных, и даже от активности/пассивности стиля получения данных.
А вы по-прежнему рассказываете про то, что лучше писать всё каждый раз руками, или использовать готовые монолитные библиотеки. Это как если бы фанат С рассказывал, что шаблонные коллекции — это какой-то непонятный механизм, и что ему нетрудно руками написать compare_values(x, y) для каждого нужного ему типа, либо вообще использовать готовую библиотеку, которая сразу умеет читать массивы double из файла и сортировать их оптимальным образом.

Меня вот, к примеру, бесит, что все механизмы по работе с XML, к примеру, построены на DOM модели. Это означает, что я не могу написать эффективный код по потоковому разбору приезжаюшего на сервер потока в реактивном режиме. Точнее, могу — если перейду на SAX парсер и буду всё читать руками. Ничего из готового кода по десериализации, валидации, или XPath работать не будет. Там всё построено на том, что надо активно дрючить Document, который обязан быть готов к моменту начала работы. А я бы хотел иметь всё наоборот — чтобы у меня был реактивный XPath Expression, который выплёвает найденную Node в виде события каждый раз, как только она готова; чтобы он работал поверх SAX-парсера, который запихивает в этот XPath прочитанные элементы в виде событий, и тоже работает поверх "обратного streamreader", который запихивает в парсер читаемый текст по мере готовности. И, естественно, streamreader тоже должен работать "наоборот", т.е. не вызывать stream.Read(), а ждать от реактивного stream события DataArrived.
Всё это можно сделать, вот только
1. объём работы огромен: процитированная иерархия — это чуть менее, чем "до хрена" кода, при этом переписать его в реактивном стиле не вполне тривиально.
2. результат работы — дубирование кода. То есть надо будет править ошибки параллельно в двух реализациях StreamReader, XmlDocument, и XPathExpression.

Хочется обратного: чтобы я написал код в понятном виде. А уже среда/библиотеки/хрен его знает что автоматически сгенерировала хоть активную, хоть реактивную версии.
Вот Rx — это первый известный мне подход к весу.

Он, к сожалению, никак не отвечает на многие конкретные вопросы. В частности, запись правил парсинга на нём далеко не идеальна, хоть и лучше многих альтернативных вариантов. Или, скажем, попытаться написать на нём хотя бы реактивный RegEx я бы не взялся.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.12.13 06:38
Оценка: 16 (2)
Здравствуйте, alex_public, Вы писали:


_>Возращает double. Но не в этом суть. Так получается что уже не для всех случаев полезны монады? )))

Суть в том, что если у вас нету монад, то при желании уметь отложенное вычисление sin и exp вам придётся писать отдельную функцию exp(Promise<double>) и sin(Promise<double>).
А с монадами у вас есть универсальный способ написать только double-версию sin() и exp(), и бесплатно получить sin(exp(List<double>), sin(exp(Promise<double>)), sin(exp(Promise<List<double>>)) и так далее.
Частный случай такого отжига — lifted operators — встроен в C#. То есть вам не нужно руками писать операторы сравнения для Nullable<MyType>, потому что их вы получите бесплатно из написанных вами операторов сравнения для MyType.
Монады позволяют получить то же счастье для любых типов, а не только для оборудованных compiler magic.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 30.12.13 10:39
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Совершенно верно. Вот я и хочу увидеть конкретный вид этой абстракции, чтобы оценить почему имеются проблемы (если имеются) с её реализацией на языках типа C++.


liftM2 f a b = a >>= \a -> b >>= \b -> return $ f a b


Реализовать ее в принципе можно, я-то говорил, что у нее будет несодержательный с точки зрения практической пользы тип (по крайней мере пока в C++ концептов нет).

_>Имя не принципиально. Даже если переименовать sql, он всё равно останется со своей огромной кучей проблем и ограничений. Для узкого круга задач (типа работы с таблицами и то желательно без join'ов) он ещё более менее подходит, но linq то позиционируется гораздо шире...


Тогда я вообще не понимаю, о чем вы говорите. Где LINQ и где SQL? Какое отношения ограничения sql-я имеют к linq? Какие-там базовые примитивы — если комбинаторы самому писать можно?

_>Не, ну так специализированные библиотеки под особые задачи с концепциями типа монад есть и на C++. Но применяются то они только в этих самых особых случаях. В то время как в том же Хаскеле трудно найти приложение без монад.


Ну так я объяснил почему: неудобств связанных с применением монад и вообще написанием обобщенного кода в хаскеле меньше.

_>Возращает double. Но не в этом суть. Так получается что уже не для всех случаев полезны монады? )))


Суть как раз в этом. Если у вас exp возвращает double, то принимая числа даже меньше 1000 он уже возвращает ерунду. Просто система обработки ерунды встроена в операции с плавучкой. Понятно, что для большинства типов такой автоматической обработки нет и ее нужно организовывать. Кроме того, я сразу написал, что монады нужны для комбинирования функций вида a -> m b, и там же написал что полезно для комбинирования функций других видов. Мне теперь это повторять в каждом предложении?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[20]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 30.12.13 11:22
Оценка: 12 (1)
Здравствуйте, alex_public, Вы писали:

_>Ну так можно какой-нибудь пример увидеть? ) Т.е. дело даже не в конкретном коде, а в конкретном позитивном эффекте, который возникает от этих возможностей.


Ну вы же сами видели пример и даже уже его высоко оценили. Вот вы пишете: "классический ленивый декларативный Хаскель (там где он такой применим) обычно обходит другие языки по выразительности", т.е. тот код, который вы называете "классическим ленивым декларативным" обходит главным образром потому, что в хаскеле эффекты под контролем. Без этого невозможно было бы ни сделать удобное комбинирование функций, ни обеспечить более-менее разумную производительность для такого кода. Вы считаете, что "его монадная часть (подразумевая IO/ST) скорее наоборот, заметно менее удобна", но на эту монадную часть распространяются основные плюсы: о функциях можно рассуждать как о функциях, легко преобразовывать код как вручную, так и правилами перезаписи и т.д.

_>С wxWidgets всегда идёт в поставке куча примеров. Что в оригинальной (которая на C++), что в wxHaskell. Так вот если мы откроем эти примеры, то мы увидим:


_>1. код примеров из wxHaskell очень не похож на классический красивый Хаскель, который обычно показывают в учебниках (да, да, те самые факториалы и не только).

_>2. код примеров из wxHaskell выглядит менее симпатично чем их точных аналогов из примеров wxWidgets.

Ну и где сравнение про которое я спрашивал. Чтоб слева код на хаскеле, а справа, на чудо-языке в котором код существенно лучше. Вы с первого айфона что-ли пишете, или где там еще копипаст не доступен?
Допустим, вот учебный пример, использующий wxHaskell:

{-----------------------------------------------------------------------------
    reactive-banana-wx
    
    Example:
    Asteroids, adapted from
        http://www.haskell.org/haskellwiki/WxAsteroids
    
    The original example has a few graphics issues
    and I didn't put much work into correcting them.
    For more, see also 
    https://github.com/killerswan/wxAsteroids/issues/1
    http://comments.gmane.org/gmane.comp.lang.haskell.wxhaskell.general/1086
------------------------------------------------------------------------------}
{-# LANGUAGE ScopedTypeVariables #-} -- allows "forall t. Moment t"

import Graphics.UI.WX hiding (Event)
import Graphics.UI.WXCore as WXCore
import Reactive.Banana
import Reactive.Banana.WX
import System.Random

import Paths (getDataFile)

{-----------------------------------------------------------------------------
    Main
------------------------------------------------------------------------------}
-- constants
height, width, diameter :: Int
height   = 300
width    = 300
diameter = 24

chance   :: Double 
chance   = 0.1

rock, burning, ship :: Bitmap ()
rock    = bitmap $ getDataFile "rock.ico"
burning = bitmap $ getDataFile "burning.ico"
ship    = bitmap $ getDataFile "ship.ico"

explode :: WXCore.Sound ()
explode = sound $ getDataFile "explode.wav" 

main :: IO ()
main = start asteroids

{-----------------------------------------------------------------------------
    Game Logic 
------------------------------------------------------------------------------}
-- main game function
asteroids :: IO ()
asteroids = do
    ff <- frame [ text       := "Asteroids"
                , bgcolor    := white
                , resizeable := False ]

    status <- statusField [text := "Welcome to asteroids"] 
    set ff [statusBar := [status]] 

    t  <- timer ff [ interval   := 50 ]

    game  <- menuPane      [ text := "&Game" ] 
    new   <- menuItem game [ text := "&New\tCtrl+N", help := "New game" ]
    pause <- menuItem game [ text      := "&Pause\tCtrl+P" 
                           , help      := "Pause game" 
                           , checkable := True
                           ] 
    menuLine game
    quit  <- menuQuit game [help := "Quit the game"] 
    
    set new   [on command := asteroids] 
    set pause [on command := set t [enabled :~ not]] 
    set quit  [on command := close ff]
    
    set ff [menuBar := [game]]
    
    pp <- panel ff []
    set ff [ layout  := minsize (sz width height) $ widget pp ]
    set pp [ on (charKey '-') := set t [interval :~ \i -> i * 2] 
           , on (charKey '+') := set t [interval :~ \i -> max 10 (div i 2)] 
           ]
    
    -- event network
    let networkDescription :: forall t. Frameworks t => Moment t ()
        networkDescription = do
            -- timer
            etick  <- event0 t command
    
            -- keyboard events
            ekey   <- event1 pp keyboard
            let eleft  = filterE ((== KeyLeft ) . keyKey) ekey
                eright = filterE ((== KeyRight) . keyKey) ekey
        
            -- ship position
            let
                bship :: Behavior t Int
                bship = accumB (width `div` 2) $
                    (goLeft <$ eleft) `union` (goRight <$ eright)
            
                goLeft  x = max 0          (x - 5)
                goRight x = min (width-30) (x + 5)
        
            -- rocks
            brandom <- fromPoll (randomRIO (0,1) :: IO Double)
            let
                brocks :: Behavior t [Rock]
                brocks = accumB [] $
                    (advanceRocks <$ etick) `union`
                    (newRock <$> filterE (< chance) (brandom <@ etick))
        
            -- draw the game state
            sink pp [on paint :== stepper (\_dc _ -> return ()) $
                     (drawGameState <$> bship <*> brocks) <@ etick]
            reactimate $ repaint pp <$ etick
        
            -- status bar
            let bstatus :: Behavior t String
                bstatus = (\r -> "rocks: " ++ show (length r)) <$> brocks
            sink status [text :== bstatus]
    
    network <- compile networkDescription    
    actuate network


-- rock logic
type Position = Point2 Int
type Rock     = [Position] -- lazy list of future y-positions

newRock :: Double -> [Rock] -> [Rock]
newRock r rs = (track . floor $ fromIntegral width * r / chance) : rs

track :: Int -> Rock
track x = [point x (y - diameter) | y <- [0, 6 .. height + 2 * diameter]]

advanceRocks :: [Rock] -> [Rock]
advanceRocks = filter (not . null) . map (drop 1)



-- draw game state
drawGameState :: Int -> [Rock] -> DC a -> b -> IO ()
drawGameState ship rocks dc _view = do
    let
        shipLocation = point ship (height - 2 * diameter)
        positions    = map head rocks
        collisions   = map (collide shipLocation) positions

    drawShip dc shipLocation
    mapM (drawRock dc) (zip positions collisions) 

    when (or collisions) (play explode)

collide :: Position -> Position -> Bool
collide pos0 pos1 = 
    let distance = vecLength (vecBetween pos0 pos1) 
    in distance <= fromIntegral diameter 

drawShip :: DC a -> Point -> IO ()
drawShip dc pos = drawBitmap dc ship pos True [] 

drawRock :: DC a -> (Point, Bool) -> IO ()
drawRock dc (pos, collides) = 
    let rockPicture = if collides then burning else rock
    in drawBitmap dc rockPicture pos True []

Можете вы пояснить, что тут так не похоже на "классический" хаскель и "красивый код в учебниках" (ну, кроме того, что автор по какой-то причуде использует let in вместо where), что тут конкретно нужно поменять, чтоб это выглядело также как некий не называемый красивый код?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[20]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 31.12.13 12:59
Оценка:
Здравствуйте, alex_public, Вы писали:

K>>Да любой код, про который вы решите, что он лучше кода на языке икс — лучше, в конечном счете, как раз потому, что в хаскеле есть IO/ST


_>Ну так можно какой-нибудь пример увидеть? ) Т.е. дело даже не в конкретном коде, а в конкретном позитивном эффекте, который возникает от этих возможностей.


В кратце это будет реактивный/асинхронный паттерн матчинг. Тебе по идее в курсе, для чего нужен сам паттерн матчинг ?

Вот прямо сейчас есть хрень с логированием. Задача простая — разгрести логи что бы вместо хрензнаетсколькомегабайтной простыни было ровно то, что требуется, а именно — "callStack" некоторых асинхронных операций

Приходят эвенты кусочками, в них есть всякое, json, прямо код на джаваскрипте а так же всякая штукенция навроде begin-end только вариантов много, ибо старался каждый как мог, например Init -Destroy или on-un, startSync-endSync
Соответсвенно для каждой пары надо сделать небольшой процессинг, отдельно json и javascript обработать

Фокус в том, что приходит это кусочками, как построчно, так и простынями, вперемешку с мусоров от самых разных подсистем, т.е. надо
1 фильтровать-преобразовывать на уровне блоков
2 фильтровать-преобразовывать на уровне строк
3 фильтровать-преобразовывать на уровне подсистем
4 уметь работать с полу-языками
5 уметь работать с json
6 уметь работать с javascript

вот например идет такой блок
function name(value){
...
}


Он будет перемешан с кучей мусора и мусор может быть и в начале и в конце строке
надо оставить только name, если он внутри блока pir который унутре startSync-endSync
фокус такой — блок придет не одной строкой,а несколькими

т.е. может прийти function name а потом () { потом кусочками тело, потом вклинится лог какой нибудь хрени потом остаток тела и }
примерно так

D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 66: startSync { ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 80: pir:function ts:123374637463 
I/Web Console(11863): sync:getSyncStatus ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 80: pir: something ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 80:() { ts:123374637463
I/Web Console(11863): sync:getSyncStatus ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 80:.... ) { ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 80: } ) { ts:123374637463
I/Web Console(11863): sync:getSyncStatus ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 66:endSync { ts:123374637463


надо получить something, при том что брать нужно только функцию верхнего уровня, на вложеные забить


С реактивным парсингом это не составляет никаких проблем:

Вот упрощенное решение
var text = pattern('D/Web Console($number()$) content://jsHybugger.org/jshybugger.js: Line $number()$:');

// text теоретически можно задать регэкспом, но это будет выглядеть крайне коряво и трудно ловить ошибки

var systemId = word('D/Web Console');

//тоже самое

filter(systemId)
.strip(text)
.strip(timeStamp())
.takeWhen(between(word('startSync'),optional(second('pir', jsFunction('takeName()'))),word('endSync')))
.next(sendTo(screen()).color('blue'))



Итого отфильтровать по ид подсистемы, стрипнуть мусор по паттерну, остаток взять если подходит подходит под паттерн startSync — endSync и унутре у него будет function name() {...}
Далее кинуть всё в консоль покрасив синим цветом

Вот и нарисовался асинхронный паттерн матчинг/ процессинг на парсер комбинаторах. Если мне нужно чтото другое, я тут же поменял текст и не надо приседать с lexx, yacc или boost.spirit, всё прямо в консоли

Покажи хотя бы примерно, как ты будешь решать ту же задачу, если, скажем, лог идет постоянно, не выключаясь и нужно видеть актуальное состояние прямо сейчас.
Ну и напиши приблизительный конечный скрипт который будет делать ровно то, что я описал выше
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 31.12.13 13:26
Оценка: 102 (1)
Здравствуйте, Sinclair, Вы писали:

S>Он, к сожалению, никак не отвечает на многие конкретные вопросы. В частности, запись правил парсинга на нём далеко не идеальна, хоть и лучше многих альтернативных вариантов. Или, скажем, попытаться написать на нём хотя бы реактивный RegEx я бы не взялся.


Смотря что надо, вот парсер чисел в формате с плавающей запятой

/*
 Число = ["+"|"-"]НатЧисло["."[НатЧисло]][("e"|"E")["+"|"-"]НатЧисло].
 НатЧисло = Цифра{Цифра}.
 Цифра = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9".
*/

// грамматика + преобразования в строку, чисто для теста
        var digit = range('0..9');
        var natNumber = rep1(digit).map(toString);
        var sign = anyOrNone('+-');
        var fraction = optional(all(char('.'), natNumber)).map(toString);
        var exp = optional(all(anyOrNone('eE'), sign, natNumber)).map(toString);
        var number = all(sign, natNumber, fraction, exp).map(toString);

// парсинг        
        var stream = Stream.from('-012.12E-10zzzzz'.split(''));

        stream.parse(number).on('next', function(result){
// ассерты
            assert(result != null);
            assert(result.value == '-012.12E-10');
            assert(result.rest == 'zzzzz');
        });
        
        stream.fire();


Либа, правда, для продакшна не готова, на досуге я на ней монады отращиваю Собтсвенно реактивность сильно слабая, куча косяков, багов и прочих вещей, стыдно даже показывать
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 02.01.14 14:19
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Вы не написали такого кода. Вы написали совсем другой код, в котором никакого Analyze нету, и который построен на разрушающих изменениях локального состояния.


Естественно, потому как при использование for'a вынесение кода в отдельную функцию не приносит никакой пользы. Но мне почему-то казалось, что на данном форуме ни у кого не может быть проблем с мысленным преобразованием такого кода
int prev=0, count=0;
bool up=true;
for(;;){
    const int val=rand(), change=val-prev;
    string alert;
    if(up&&change>0||!up&&change<0) count++;
    else{
        if(count>=2&&change>21) alert="\tup";
        if(count>=2&&change<-11) alert="\tdown";
        count=1;
        up=change>0;
    }
    cout<<val<<alert<<endl;
    prev=val;
    this_thread::sleep_for(chrono::seconds(1));
}

в такой
void Analyze(int val)
{
    static int prev=0, count=0;
    static bool up=true;
    const int change=val-prev;
    string alert;
    if(up&&change>0||!up&&change<0) count++;
    else{
        if(count>=2&&change>21) alert="\tup";
        if(count>=2&&change<-11) alert="\tdown";
        count=1;
        up=change>0;
    }
    cout<<val<<alert<<endl;
    prev=val;
}
for(;;){
    Analyze(rand());
    this_thread::sleep_for(chrono::seconds(1));
}


Ну если кому-то это сложно, то сорри... )

S>Пока что никакой функции нету. Есть гипотетическая функция, которая конкурирует в обсуждении с конкретным, уже работающим кодом.


Этот тоже работающий — я другой не показываю. )))

S>Нам не нужен конечный автомат. Точно так же, как нам не нужен стек для арифметики — удобнее просто писать арифметические выражения в школьной нотации.

S>Конечный (или бесконечный) автомат — это деталь реализации. А нам нужна возможность записать реакцию на события в понятном виде.
S>Ваш оппонент просто пытается вам объяснить, что с точки зрения декларативной семантики парсинг активно-читаемого текста и анализ цепочек событий — одно и то же, поэтому рулят системы, которые отделяют запись правил анализа от механизмов получения данных, и даже от активности/пассивности стиля получения данных.

1. Ну так вообще то как раз я и показывал вариант, в котором всё разделено. Имеем функцию Analyze. Её можно вызвать хоть из цикла (активно), хоть как реакцию на сообщения (реактивно). Далее, в самой функции мы можем и написать ручной код (в простых случаях), и вставить мощный конечный автомат на базе какой-то библиотеки, и вставить вообще готовое решения для анализа данных на базе какого-то удобного синтаксиса задания грамматики. Вот это действительно раздельная архитектура, обеспечивающая гибкость и удобство. А как раз Rx на фоне этого выглядит монолитной хренью заточенной только под один узкий вариант.
2. Если говорить конкретно о процессе анализа, то идея записывать "грамматику" через sql операторы — это на мой взгляд полная дикость.

S>Меня вот, к примеру, бесит, что все механизмы по работе с XML, к примеру, построены на DOM модели. Это означает, что я не могу написать эффективный код по потоковому разбору приезжаюшего на сервер потока в реактивном режиме. Точнее, могу — если перейду на SAX парсер и буду всё читать руками. Ничего из готового кода по десериализации, валидации, или XPath работать не будет. Там всё построено на том, что надо активно дрючить Document, который обязан быть готов к моменту начала работы. А я бы хотел иметь всё наоборот — чтобы у меня был реактивный XPath Expression, который выплёвает найденную Node в виде события каждый раз, как только она готова; чтобы он работал поверх SAX-парсера, который запихивает в этот XPath прочитанные элементы в виде событий, и тоже работает поверх "обратного streamreader", который запихивает в парсер читаемый текст по мере готовности. И, естественно, streamreader тоже должен работать "наоборот", т.е. не вызывать stream.Read(), а ждать от реактивного stream события DataArrived.

S>Всё это можно сделать, вот только
S>1. объём работы огромен: процитированная иерархия — это чуть менее, чем "до хрена" кода, при этом переписать его в реактивном стиле не вполне тривиально.
S>2. результат работы — дубирование кода. То есть надо будет править ошибки параллельно в двух реализациях StreamReader, XmlDocument, и XPathExpression.

Несколько сомнительная идея. Потому как непонятно о чём должны сигнализировать сообщения парсера. Если о приходе узлов, то как бы всё равно получится что придёт только одно сообщение на документ, причём опять же только после прихода всего документа. Если же парсер будет сигнализировать о "начале узла", то тогда это получается только небольшая часть анализа и непонятно зачем такое вообще может быть нужно.
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 02.01.14 14:57
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Суть в том, что если у вас нету монад, то при желании уметь отложенное вычисление sin и exp вам придётся писать отдельную функцию exp(Promise<double>) и sin(Promise<double>).

S>А с монадами у вас есть универсальный способ написать только double-версию sin() и exp(), и бесплатно получить sin(exp(List<double>), sin(exp(Promise<double>)), sin(exp(Promise<List<double>>)) и так далее.

Вообще то это у нас описание функторов, а не монад. Но даже если бы это были монады... Какой смысл в протягивание этой дополнительной сущности между sin(exp()), когда можно это сделать по "краям"? )
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 02.01.14 15:08
Оценка:
Здравствуйте, alex_public, Вы писали:

_>в такой

_>
_>void Analyze(int val)
_>{
_>    static int prev=0, count=0;
_>    static bool up=true;
_>    const int change=val-prev;
_>    string alert;
_>    if(up&&change>0||!up&&change<0) count++;
_>    else{
_>        if(count>=2&&change>21) alert="\tup";
_>        if(count>=2&&change<-11) alert="\tdown";
_>        count=1;
_>        up=change>0;
_>    }
_>    cout<<val<<alert<<endl;
_>    prev=val;
_>}
_>for(;;){
_>    Analyze(rand());
_>    this_thread::sleep_for(chrono::seconds(1));
_>}
_>


_>Ну если кому-то это сложно, то сорри... )


Давай чуток усложним задачу — есть 10 потоков или асинхронных ниток и каждая должна трекать определенный источник.
С моим примером все в порядке, а твой надо переписывать
Это понятно или надо объяснять ?

Далее интереснее, алёрты надо кидать
1 скорость изменения сигнала
2 ускорение изменения сигнала
3 текущий уровень всех потоков выше или ниже определенного уровня
4 максимальный пик между двумя максимальными спадами.
5 плато

Опиши хотя бы что тебе понядобится и насколько код усложнится.

S>>Пока что никакой функции нету. Есть гипотетическая функция, которая конкурирует в обсуждении с конкретным, уже работающим кодом.


_>1. Ну так вообще то как раз я и показывал вариант, в котором всё разделено. Имеем функцию Analyze. Её можно вызвать хоть из цикла (активно), хоть как реакцию на сообщения (реактивно). Далее, в самой функции мы можем и написать ручной код (в простых случаях), и вставить мощный конечный автомат на базе какой-то библиотеки, и вставить вообще готовое решения для анализа данных на базе какого-то удобного синтаксиса задания грамматики. Вот это действительно раздельная архитектура, обеспечивающая гибкость и удобство. А как раз Rx на фоне этого выглядит монолитной хренью заточенной только под один узкий вариант.


Наоборот, это у тебя только один вариант. Твоя функция Analyze это полностью энергичный код, а у меня она ленивая. Соответсвенно скорость посчитать очень легко, а тебе надо приседать и приседать.

S>>2. результат работы — дубирование кода. То есть надо будет править ошибки параллельно в двух реализациях StreamReader, XmlDocument, и XPathExpression.


_>Несколько сомнительная идея. Потому как непонятно о чём должны сигнализировать сообщения парсера. Если о приходе узлов, то как бы всё равно получится что придёт только одно сообщение на документ, причём опять же только после прихода всего документа. Если же парсер будет сигнализировать о "начале узла", то тогда это получается только небольшая часть анализа и непонятно зачем такое вообще может быть нужно.


Очень просто — например тебе надо на лету стрипать определенный контент. Что это может быть и в каких узлах — дело десятое. Например xml читается одним источником, обрабатывается и тут же отдаётся куда нибудь, все это делается одновременно. DOM здесь не поможет, т.е. данные целиком никогда не будут загружены.
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 02.01.14 15:33
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>liftM2 f a b = a >>= \a -> b >>= \b -> return $ f a b

Ага... Ну так тут мы используем знания о типе конкретной монады используя определённый для неё оператор >>=. Если в C++ определить для каждого типа монад такой же оператор, то не будет вообще никаких проблем в аналогичной записи liftM2.

Т.е. например для boost.optional мы определим >>= как
template<typename T, typename F>
auto operator>>=(optional<T> o, F f)->decltype(f(*o)){return f(*o);}

и без проблем записываем liftM2 как
template<template<class>class M, typename R, typename T1, typename T2>
function<M<R>(M<T1>,M<T2>)> liftM2(R (*f)(T1, T2))
{return [=](M<T1> tm1, M<T2> tm2){return tm1>>=[&](T1 t1){return tm2>>=[&](T2 t2)->M<R>{return f(t1, t2);};};};}


И можем протестировать например так:
string add(int v1, double v2) {return to_string(v1+v2);}
cout<<*liftM2<optional>(add)(optional<int>(3), optional<double>(7))<<endl;//выводит 10,000000

Более того, мы можем взять совсем другую монаду, например listM и для той же самой функции add (не говоря уже о liftM2) получим
for(auto& i: liftM2<listM>(add)(listM<int>{1, 2, 3}, listM<double>{3.0, 6.0, 9.0})) cout<<i<<' ';
//выводит 4,000000 7,000000 10,000000 5,000000 8,000000 11,000000 6,000000 9,000000 12,000000


K>Реализовать ее в принципе можно, я-то говорил, что у нее будет несодержательный с точки зрения практической пользы тип (по крайней мере пока в C++ концептов нет).


И в чём несодержательность то? ) Обе функции выглядят один в один, разве что вариант на C++ имеет гораздо больше всякие скобочек и т.п. Если основная претензия к этому, то я в общем то соглашусь. ))) Но насчёт несодержательности непонятно что-то... )

K>Тогда я вообще не понимаю, о чем вы говорите. Где LINQ и где SQL? Какое отношения ограничения sql-я имеют к linq? Какие-там базовые примитивы — если комбинаторы самому писать можно?


Писать то можно... Только кто это делает? ) Почему я вижу определение грамматики через select, where и т.п.? )

K>Суть как раз в этом. Если у вас exp возвращает double, то принимая числа даже меньше 1000 он уже возвращает ерунду. Просто система обработки ерунды встроена в операции с плавучкой. Понятно, что для большинства типов такой автоматической обработки нет и ее нужно организовывать. Кроме того, я сразу написал, что монады нужны для комбинирования функций вида a -> m b, и там же написал что полезно для комбинирования функций других видов. Мне теперь это повторять в каждом предложении?


Суть в том, что на практике монады как раз нужны достаточно редко. А их частое использование в Хаскеле всего лишь следствие некоторых неудобностей языка (которые являются ценой за некоторые особенности, возможно приносящие плюсы, а возможно и нет — это мы так и не выяснили пока).
Re[21]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 02.01.14 15:49
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Ну вы же сами видели пример и даже уже его высоко оценили. Вот вы пишете: "классический ленивый декларативный Хаскель (там где он такой применим) обычно обходит другие языки по выразительности", т.е. тот код, который вы называете "классическим ленивым декларативным" обходит главным образром потому, что в хаскеле эффекты под контролем. Без этого невозможно было бы ни сделать удобное комбинирование функций, ни обеспечить более-менее разумную производительность для такого кода. Вы считаете, что "его монадная часть (подразумевая IO/ST) скорее наоборот, заметно менее удобна", но на эту монадную часть распространяются основные плюсы: о функциях можно рассуждать как о функциях, легко преобразовывать код как вручную, так и правилами перезаписи и т.д.


Да, правильно, код внутри монад будет доступен из окружающего его кода в том же самом красивом режиме. Но что если у нас практически весь код приложения находится в монадах? ) Тогда в общем то эти плюсы пропадают в никуда.

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

K>Ну и где сравнение про которое я спрашивал. Чтоб слева код на хаскеле, а справа, на чудо-языке в котором код существенно лучше. Вы с первого айфона что-ли пишете, или где там еще копипаст не доступен?

K>Допустим, вот учебный пример, использующий wxHaskell:

В этом примере ещё не всё так страшно, т.к. некая часть программы занята логикой, которая выражается "нормальным" хаскелем. В реальном системном ПО или же тех же примеров из самого wxHaskell соотношение такого кода гораздо хуже. Но даже здесь хорошо видна разница между этими областями в приложение. Ну а если мы сравним этот пример с его аналогом на C++, то будет всё совсем печально.
Re[21]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 02.01.14 16:32
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>В кратце это будет реактивный/асинхронный паттерн матчинг. Тебе по идее в курсе, для чего нужен сам паттерн матчинг ?


Ага, только непонятно какое это вообще имеет отношение к плюсам возникающим из-за особенности реализации IO/ST в Хаскеле, которые мы тут обсуждали? ))) Rx то не касается этих гипотетических (пока для меня, т.к. Klapaucius пока не показал ни одного примера) плюсов ни в малейшей степени.

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

I>Ну и напиши приблизительный конечный скрипт который будет делать ровно то, что я описал выше

Ну я промолчу про подобную систему логирования... Предположим, что нам очень не повезло в жизни и реально надо возиться с подобным. Решение выглядит очевидно. Что-то вроде (это не протестированный псевдо код):
static bool show=false;
match what;
if(regex_match(str, what, regex)){//regex вырезает данные между "D/Web Console(ххххх) content://jsHybugger.org/jshybugger.js: Line хх:" и "ts:хххххххххххх"
    if(find(what[1], "endSync")) show=false;
    if(show) cout<<what[1];
    if(find(what[1], "startSync")) show=true;
}


Это без pir, т.к. я не очень понял значения кода там с optional, second и т.п. Но предполагаю, что после разъяснения постановки задачи, добавление нужного кода сведётся к одному дополнительному if'у или чему-то вроде этого. )))
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 02.01.14 17:09
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Давай чуток усложним задачу — есть 10 потоков или асинхронных ниток и каждая должна трекать определенный источник.

I>С моим примером все в порядке, а твой надо переписывать
I>Это понятно или надо объяснять ?

Если нам надо иметь несколько параллельных парсеров, то просто переделываем глобальную функцию, в функцию-член некого класса и всё. Стандартная техника и кстати код функции при этом править не надо. )))

I>Далее интереснее, алёрты надо кидать

I>1 скорость изменения сигнала
I>2 ускорение изменения сигнала
I>3 текущий уровень всех потоков выше или ниже определенного уровня
I>4 максимальный пик между двумя максимальными спадами.
I>5 плато

I>Опиши хотя бы что тебе понядобится и насколько код усложнится.


Не вижу вообще ничего сложного. Даже конечный автомат не нужен или какие-то другие библиотеки. Просто пишем соответствующий код под каждый алерт и всё. В чём проблема то? ) Там по одной строчке вычисления на каждое текущее значение, плюс по одному if'у на алерт. )))

I>Наоборот, это у тебя только один вариант. Твоя функция Analyze это полностью энергичный код, а у меня она ленивая. Соответсвенно скорость посчитать очень легко, а тебе надо приседать и приседать.


Ээээ что? ))) Скорость это всего лишь vel=val-prev;

I>Очень просто — например тебе надо на лету стрипать определенный контент. Что это может быть и в каких узлах — дело десятое. Например xml читается одним источником, обрабатывается и тут же отдаётся куда нибудь, все это делается одновременно. DOM здесь не поможет, т.е. данные целиком никогда не будут загружены.


Если нам не требуется DOM (даже в итоге), то нам и не нужен подобный подробный разбор. Достаточно банального регулярного выражения.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 02.01.14 18:16
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Если нам надо иметь несколько параллельных парсеров, то просто переделываем глобальную функцию, в функцию-член некого класса и всё. Стандартная техника и кстати код функции при этом править не надо. )))


Но переделывать то надо ? А мне даже отдельной функции заводить не надо

_>Не вижу вообще ничего сложного. Даже конечный автомат не нужен или какие-то другие библиотеки. Просто пишем соответствующий код под каждый алерт и всё. В чём проблема то? ) Там по одной строчке вычисления на каждое текущее значение, плюс по одному if'у на алерт. )))


Не получается по одной строчке на каждое условие

I>>Наоборот, это у тебя только один вариант. Твоя функция Analyze это полностью энергичный код, а у меня она ленивая. Соответсвенно скорость посчитать очень легко, а тебе надо приседать и приседать.


_>Ээээ что? ))) Скорость это всего лишь vel=val-prev;


Это _не_ скорость, а просто дельта текущего и предыдущего значений.

I>>Очень просто — например тебе надо на лету стрипать определенный контент. Что это может быть и в каких узлах — дело десятое. Например xml читается одним источником, обрабатывается и тут же отдаётся куда нибудь, все это делается одновременно. DOM здесь не поможет, т.е. данные целиком никогда не будут загружены.


_>Если нам не требуется DOM (даже в итоге), то нам и не нужен подобный подробный разбор. Достаточно банального регулярного выражения.


Это тянет на нобелевку. Пример — на регулярных выражениях правильно вырезать определенные теги, которые, внезапно, могут быть вложенными.
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 02.01.14 18:21
Оценка:
Здравствуйте, alex_public, Вы писали:

I>>В кратце это будет реактивный/асинхронный паттерн матчинг. Тебе по идее в курсе, для чего нужен сам паттерн матчинг ?


_>Ага, только непонятно какое это вообще имеет отношение к плюсам возникающим из-за особенности реализации IO/ST в Хаскеле, которые мы тут обсуждали? ))) Rx то не касается этих гипотетических (пока для меня, т.к. Klapaucius пока не показал ни одного примера) плюсов ни в малейшей степени.


Ты просто не хочешь увидеть, ибо аргументы у тебя навроде "я всё это могу на с++ тупо императивно".

Пример что я привел никакой не гипотетический.


I>>Ну и напиши приблизительный конечный скрипт который будет делать ровно то, что я описал выше


_>Ну я промолчу про подобную систему логирования... Предположим, что нам очень не повезло в жизни и реально надо возиться с подобным. Решение выглядит очевидно. Что-то вроде (это не протестированный псевдо код):

_>
_>static bool show=false;
_>match what;
_>if(regex_match(str, what, regex)){//regex вырезает данные между "D/Web Console(ххххх) content://jsHybugger.org/jshybugger.js: Line хх:" и "ts:хххххххххххх"
_>    if(find(what[1], "endSync")) show=false;
_>    if(show) cout<<what[1];
_>    if(find(what[1], "startSync")) show=true;
_>}
_>


_>Это без pir, т.к. я не очень понял значения кода там с optional, second и т.п. Но предполагаю, что после разъяснения постановки задачи, добавление нужного кода сведётся к одному дополнительному if'у или чему-то вроде этого. )))


Ты решил не ту задачу У меня разбор некоторого контекстно-свободного языка реактивным парсером.
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 02.01.14 20:25
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Ну я промолчу про подобную систему логирования... Предположим, что нам очень не повезло в жизни и реально надо возиться с подобным.


Я могу логировать ровно столко, сколько мне нужно, главное что бы разгрести эти логи. Поэтому речь не про везение, а про инструмент. Вообще, по уму, хорошо бы логировать каждую строчку, но это конечно сказка
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 04.01.14 02:31
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Но переделывать то надо ? А мне даже отдельной функции заводить не надо


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

I>Не получается по одной строчке на каждое условие


НУ это у кого как. )))

I>Это _не_ скорость, а просто дельта текущего и предыдущего значений.


Дааа? ) Т.е. у тебя замеры анализируемого значения производятся не через равные промежутки времени и в нашу функцию анализа передаётся ещё и массив значений этих интервалов? ) Потому как в противном случае дельта — это и будет скорость. )))

I>Это тянет на нобелевку. Пример — на регулярных выражениях правильно вырезать определенные теги, которые, внезапно, могут быть вложенными.


Вообще то подразумевалось, что регулярное выражение используется для нахождения момента с которого мы будем пропускать данные (у нас же потоковая обработка вроде как), а не для самого вырезания из всего объёма данных... Однако если бы мы вдруг захотели именно подобное вырезание, то оно тоже вполне реально, в том числе и для вложенных тэгов.
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 04.01.14 02:52
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Ты просто не хочешь увидеть, ибо аргументы у тебя навроде "я всё это могу на с++ тупо императивно".


Для начала давай разделять "можно на C++" и "можно императивно". Это разные вещи. Чаще всего я как раз показываю, что предложенное решение можно без проблем реализовать и в C++ прямо в оригинальном (не императивном) виде. Однако потом обычно говорю, что это всё нафиг не нужный мусор, разведённый ради мифической красоты (а в реальности для программистских "понтов") и тупой императивный код в лоб решает задачу быстрее. Причём быстрее и по итоговому коду и по времени его написания.

И кстати говоря далеко не все вещи из других языков реально повторить на C++. Например некоторые возможности реализуемые в D на C++ повторить не реально. Хотя с обычно обсуждаемым с тобой языком такого конечно быть не может, там всё наоборот. Кстати, как раз в тему... Как по твоему, реально ли написать на C# функцию liftM2 подходящую для произвольного типа монад? На Хаскеле очевидно легко. На C++ тоже без проблем, как я показал здесь http://www.rsdn.ru/forum/philosophy/5417607
Автор: alex_public
Дата: 02.01.14
.

I>Пример что я привел никакой не гипотетический.


Только он вообще не имеет никакого отношения к эффектам, на которые намекает Klapaucius...

I>Ты решил не ту задачу У меня разбор некоторого контекстно-свободного языка реактивным парсером.


Тут прямо в точности оно и есть. Мой код вызываем для каждой приходящей строки и получаем тот же результат, что и у тебя. )
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 04.01.14 02:56
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Я могу логировать ровно столко, сколько мне нужно, главное что бы разгрести эти логи. Поэтому речь не про везение, а про инструмент.


Дело не в объёме, а в оформление ужаса... ))) Ну да ладно, это уже вопрос совсем далёкий от данной темки...

I>Вообще, по уму, хорошо бы логировать каждую строчку, но это конечно сказка


Подобное "логирование" называется "отладка".
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 04.01.14 08:36
Оценка:
Здравствуйте, alex_public, Вы писали:

I>>Я могу логировать ровно столко, сколько мне нужно, главное что бы разгрести эти логи. Поэтому речь не про везение, а про инструмент.


_>Дело не в объёме, а в оформление ужаса... ))) Ну да ладно, это уже вопрос совсем далёкий от данной темки...


I>>Вообще, по уму, хорошо бы логировать каждую строчку, но это конечно сказка


_>Подобное "логирование" называется "отладка".


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