Re[6]: Решение Problem K на Эрланг: дизайн
От: BulatZiganshin  
Дата: 07.11.07 16:41
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Вообще — общий вывод такой: функциональная чистота радикально упрощает дизайн — фактически, она устраняет его как геморройную и ответственную фазу, к которой мы привыкли в ОО. Конкретнее — спасает отсутствие указателей, референсов, и изменяемого состояния. Из-за этого рефакторинг обходится дешевле на порядок — его просто не замечаешь. И дизайн элементарен — это уже не настолько трудоемкая и ответственная фаза. Думать нужно только о связности и группировке функций. Халява полная.


G>А вот с процессами мы таки получим обратно изменяемое состояние и референсы. Тогда и начнется самое интересное.


а хвостовая рекурсия? получил сигнал, пересчитал состояние и всё:

-- ход противника
chess state = do move <- getChannel c
                 chess2 (applyMove state move)

-- наш ход
chess2 state = do let move = calcOurMove state
                  putChannel c move
                  chess (applyMove state move)
Люди, я люблю вас! Будьте бдительны!!!
Re[7]: Решение Problem K на Эрланг: дизайн
От: Gaperton http://gaperton.livejournal.com
Дата: 07.11.07 16:49
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>Здравствуйте, Gaperton, Вы писали:


G>>Вообще — общий вывод такой: функциональная чистота радикально упрощает дизайн — фактически, она устраняет его как геморройную и ответственную фазу, к которой мы привыкли в ОО. Конкретнее — спасает отсутствие указателей, референсов, и изменяемого состояния. Из-за этого рефакторинг обходится дешевле на порядок — его просто не замечаешь. И дизайн элементарен — это уже не настолько трудоемкая и ответственная фаза. Думать нужно только о связности и группировке функций. Халява полная.


G>>А вот с процессами мы таки получим обратно изменяемое состояние и референсы. Тогда и начнется самое интересное.


BZ>а хвостовая рекурсия? получил сигнал, пересчитал состояние и всё:


BZ>
BZ>-- ход противника
BZ>chess state = do move <- getChannel c
BZ>                 chess2 (applyMove state move)

BZ>-- наш ход
BZ>chess2 state = do let move = calcOurMove state
BZ>                  putChannel c move
BZ>                  chess (applyMove state move)
BZ>


Это чистый код. Тут ссылок нет. В Эрланге у процесса есть identity — pid, зная который, ты можешь послать ему сообщение. Этот pid можно передавать другим процессам. А у тебя здесь identity нет. Нет identity — нет агрегирования, владения, связей, и прочих проблем.
Re[6]: Объяснение устройства cell
От: Gaperton http://gaperton.livejournal.com
Дата: 07.11.07 17:08
Оценка:
Здравствуйте, red75, Вы писали:

R>Здравствуйте, Gaperton, Вы писали:


R>>>Хм. А ведь Cell — это, в общем-то, простое хранилище, однозначно определяемое по {Ref,Table}. Почему-бы не вынести cell:evaluate, cell:eval_and_get в Table?


G>>Склеить их в принципе можно. Однако, стоит объяснить, почему они разделены.


R>Нет, я не говорю о склеивании. Связь Cell->Table осуществляется только через table:get_cell, но зачем Cell'у знать как получать значения из таблицы? Это нужно только для expression.


Интересно. А ведь и в самом деле.

G>>Только зная внутреннюю структуру типа cell, мы сможем понять, что внутри лежит формула. Перенеся этот код в модуль sheet, мы получим более сильную связность — потому что человек, разбирающийся в устройстве sheet, не сможет понять его, не разобравшись в деталях cell. А это именно то, чего мы хотим избежать.


R>Я имел в виду:

R>
R>-module(expression).
R>evaluate( { ref, Ref }, Sheet ) -> table:evaluate( Ref, Sheet );
R>-module(table).
R>evaluate(Ref,Sheet)->cell:evaluate(Ref,get_cell(Ref,Sheet)).
R>-module(cell).
R>evaluate(Ref,Cell)->и т.д.
R>


Хм-м-м... В результате одним махом убираем связь от cell к sheet, и от expression к cell. Гениально. Отлично, спасибо!

G>>Однако, cell этого не знает, плевать cell-y, как устроен expression. Он знает, что expression можно создать

G>>create( string() ) -> expression()
G>>и вычислить
G>>evaluate( Ref, expression(), sheet() ) -> { Value, sheet() }.

G>>Вот, кстати, тут виден реальный прощот. Value и Ref проходят явно в межмодульном интерфейсе. Вот это — ай-ай-ай. cell и expression слишком сильно связаны. Буду думать, как править.


R>Избавиться от передачи Ref'ов по-моему нельзя. Может запромотить его в АТД? Что-то вроде:

R>
R>-module(table).
R>%% make_ref::(integer(),integer())->ref()
R>make_ref(X,Y)->{X,Y}.
R>-module(expression).
R>create_arg( [ Row, Col ] ) when Row >= $a, Row =< $z, Col >= $0, Col =< $9 ->
R>    { ref, table:make_ref(Row - $a + 1, Col - $0) };
R>


Да, именно так я и собрался сделать. Т.е. в точности так. Вплоть до имен функций и модулей .

R>А на счёт Value бродят смутные мысли о разделении значения ячейки (формула/литерал/пусто) и вычисленного значения ячейки (число/строка/ошибка), но пока не оформились.


Именно такие мысли ходили и у меня. В первых внутримодульных тайпдефах у меня это так и разделялось — UnevaluatedCell и Cell. Однако красиво завернуть это в АДТ — я прощелкал. Просто пропустил. Заметил только сейчас, когда начал объяснять.

Вот, с твоей правкой по поводу evaluate + с решенными проблемами Value и Ref, можно будет поднять оценку дизайна с 4 (good enough) до 5 (perfect).

Прикольно дизайнить для Эрланга, правда? Ничего нет кроме модулей и функций, а насколько дофига оказывается можно сделать! Даже налажать можно .
Re[8]: Решение Problem K на Эрланг: дизайн
От: BulatZiganshin  
Дата: 07.11.07 17:37
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Это чистый код. Тут ссылок нет.


именно об этом я и говорю

>В Эрланге у процесса есть identity — pid, зная который, ты можешь послать ему сообщение. Этот pid можно передавать другим процессам. А у тебя здесь identity нет. Нет identity — нет агрегирования, владения, связей, и прочих проблем.


а на пальцах показать? с чистыми данными такая проблема — это и есть данные. хочешь — шахматную доску передавай, хочешь — состояние ядерного реактора. "не будет ни радио, ни газет, ни кино — одно сплощное телевидение"
Люди, я люблю вас! Будьте бдительны!!!
Re[9]: Решение Problem K на Эрланг: дизайн
От: Gaperton http://gaperton.livejournal.com
Дата: 07.11.07 18:34
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>Здравствуйте, Gaperton, Вы писали:


G>>Это чистый код. Тут ссылок нет.


BZ>именно об этом я и говорю


>>В Эрланге у процесса есть identity — pid, зная который, ты можешь послать ему сообщение. Этот pid можно передавать другим процессам. А у тебя здесь identity нет. Нет identity — нет агрегирования, владения, связей, и прочих проблем.


BZ>а на пальцах показать? с чистыми данными такая проблема — это и есть данные. хочешь — шахматную доску передавай, хочешь — состояние ядерного реактора. "не будет ни радио, ни газет, ни кино — одно сплощное телевидение"



-module( my_object ).

-record( this, { member1 = "a", member2 = 1, ... } ).

new() ->spawn( fun dispatch/1, #members{} ).

set( This, Attribute, Value ) -> This ! { set, Attribute, Value }.
get( This, Attribute, Value ) ->
   This ! { get, Attribute, self() },
   receive { return, This, Value } -> Value end.

dispatch( Members ) ->
   NewState = receive
      { set, member1, Value } -> Members#this{ member1 = Value };
      { get, member1, Caller } -> Caller ! { return, self(), Members#this.member1 }, Members;
   ...
   end,
   dispatch( NewState ).

-module( caller ).
...
   Obj = my_object:new(),
   "a" = my_object:get( Obj, member1 )
   my_object:set( Obj, member1, "b" ),
...
   "a" = my_object:get( Obj, member1 ), %% Ой! Эксцепшн bad_match! Значение то у нас вернулось - "b"!
Re[3]: Код expression, sheet, cell: задачка
От: Трурль  
Дата: 07.11.07 19:10
Оценка: 39 (1)
Здравствуйте, Gaperton, Вы писали:

G>Так не получится. Вся сложность в алгоритме expression. Он вычисляет клетки рекурсивно. Когда он встречает в аргументе reference, ему надо вычислить значение в клетке, а там также может быть expression. Отсюда протягивается обратная ссылка на cell.


Каюсь, первая мысль была передавать в expression:evaluate функцию-разыменователь
evaluate(expression(), Ref->Value ) -> Value.

Это, конечно, плохо – нельзя исключить перевычислений и к тому же ни разу не идиоматически.

Но что если дать возможность узнать, на что ссылается выражение и передавать контекст для его вычисления?
module( expression ).
-export( [ create/1, evaluate/2, refs/1 ] ).

create( string() ) -> expression().

refs(expression()) -> [ Ref ].
evaluate(expression(), dictionary() ) -> Val.

А обновлениями ячеек и порядком вычислений пусть рулит sheet.
Re[4]: Код expression, sheet, cell: задачка
От: Gaperton http://gaperton.livejournal.com
Дата: 07.11.07 19:43
Оценка:
Здравствуйте, Трурль, Вы писали:

Т>Но что если дать возможность узнать, на что ссылается выражение и передавать контекст для его вычисления?

Т>
Т>module( expression ).
Т>-export( [ create/1, evaluate/2, refs/1 ] ).

Т>create( string() ) -> expression().

Т>refs(expression()) -> [ Ref ].
Т>evaluate(expression(), dictionary() ) -> Val.
Т>

Т>А обновлениями ячеек и порядком вычислений пусть рулит sheet.

Неплохо. Я с самого начала мельком подумал о таком подходе, но почему-то сразу его отмел и решил делать тупо — тот же алгоритм, как в плюсах. Однако, получается интересно.

Можно обойтись и простым списком значений — без dictionary. Тогда реально все вытягивается в трубу. Ты имеешь в виду вот это?

-module( sheet ).

evaluate( Ref, Sheet ) ->
   Value = get_cell( Ref, Sheet ), % цыклы не ловим, ломает. Понятно, как, но лень
   { Context, NewSheet }= mapfoldl( fun evaluate/2, Sheet, cell:dependency_list( Value ) ),
   NewValue = cell:evaluate( Value, Context ),
   { NewValue, set_cell( Ref, NewValue ) }.
...

-module( cell ). %% как-то больно тупо стал выглядеть этот модуль. :)
depencency_list( { expression, Expr } ) -> expression:depencency_list( Expr );
depencency_list( _ ) -> [].

evaluate( { expression, Expr }, Context ) -> expression:evaluate( Expr, Context );
evaluate( Value, [] ) -> Value.

...

-module( expression ).

depencency_list( { _Expr, Refs } ) -> Refs.
evaluate( { ref, _ }, [ Value | Rest ] ) -> { Value, Context }
...
evaluate( Num, Context ) -> { Num, Context }
...


Это решение мне нравится существенно больше лобовой реализации типического плюсового алгоритма, как у меня. Попробую реализовать и этот вариант, как будет время.

Декоративное программирование рулит!
Re[10]: Решение Problem K на Эрланг: дизайн
От: BulatZiganshin  
Дата: 07.11.07 19:53
Оценка:
Здравствуйте, Gaperton, Вы писали:

BZ>>а на пальцах показать? с чистыми данными такая проблема — это и есть данные. хочешь — шахматную доску передавай, хочешь — состояние ядерного реактора. "не будет ни радио, ни газет, ни кино — одно сплощное телевидение"


для меня этот некомментированный код — не на пальцах
Люди, я люблю вас! Будьте бдительны!!!
Re[11]: Решение Problem K на Эрланг: дизайн
От: Gaperton http://gaperton.livejournal.com
Дата: 07.11.07 20:46
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>Здравствуйте, Gaperton, Вы писали:


BZ>>>а на пальцах показать? с чистыми данными такая проблема — это и есть данные. хочешь — шахматную доску передавай, хочешь — состояние ядерного реактора. "не будет ни радио, ни газет, ни кино — одно сплощное телевидение"


BZ>для меня этот некомментированный код — не на пальцах


spawn — создает процесс, берет параметром функцию, которая будет вызвана этим процессом, возвращает PID.

PID ! Message — отправляет процессу PID сообщение Message

receive — оператор блокирующего ожидания сообщения, соответствующего заданному паттерну.

Подробности в Эрланг референс мануал.
http://erlang.org/doc/reference_manual/part_frame.html
Re[7]: Объяснение устройства cell
От: red75  
Дата: 08.11.07 05:14
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Да, именно так я и собрался сделать. Т.е. в точности так. Вплоть до имен функций и модулей .




R>>А на счёт Value бродят смутные мысли о разделении значения ячейки (формула/литерал/пусто) и вычисленного значения ячейки (число/строка/ошибка), но пока не оформились.


G>Именно такие мысли ходили и у меня. В первых внутримодульных тайпдефах у меня это так и разделялось — UnevaluatedCell и Cell. Однако красиво завернуть это в АДТ — я прощелкал. Просто пропустил. Заметил только сейчас, когда начал объяснять.


G>Вот, с твоей правкой по поводу evaluate + с решенными проблемами Value и Ref, можно будет поднять оценку дизайна с 4 (good enough) до 5 (perfect).


Насчёт Value: ими ведь занимается только Expression? Добавить туда (в expression) конструкторы Value и преобразование Value->string, ну а Cell будет хранить Value|expression().

G>Прикольно дизайнить для Эрланга, правда? Ничего нет кроме модулей и функций, а насколько дофига оказывается можно сделать! Даже налажать можно .


Эт точно. Впрочем минимизация связности — NP-задача. ХЗ как мы её вообще решаем .
Re[8]: Объяснение устройства cell
От: Курилка Россия http://kirya.narod.ru/
Дата: 08.11.07 06:25
Оценка:
Здравствуйте, red75, Вы писали:

R>Здравствуйте, Gaperton, Вы писали:


G>>Прикольно дизайнить для Эрланга, правда? Ничего нет кроме модулей и функций, а насколько дофига оказывается можно сделать! Даже налажать можно .


R>Эт точно. Впрочем минимизация связности — NP-задача. ХЗ как мы её вообще решаем .


А вообще, интересно есть какие-либо исследования/книги посвящённые этой теме? Что-нибудь с обобщённой точки зрения на вопрос, а не конретика по языкам и т.п.?
Или в основном это на базе интуиции? Но даже если так, то должны же быть какие-нибудь эвристики или типа того...
Re[3]: Код expression, sheet, cell: задачка
От: sergesokolov Россия http://www.ideashag.spb.ru
Дата: 08.11.07 07:22
Оценка: -1
Здравствуйте, Gaperton, Вы писали:

G>Здравствуйте, Трурль, Вы писали:


G>>>Может я чего-то не учел, но связи можно сделать и попроще.


Т>>
Т>>main -> sheet -> cell -> expression -> operation
Т>>


G>Так не получится. Вся сложность в алгоритме expression. Он вычисляет клетки рекурсивно. Когда он встречает в аргументе reference, ему надо вычислить значение в клетке, а там также может быть expression. Отсюда протягивается обратная ссылка на cell. Придется мне привести код, чтобы стало понятно.


G>Кстати, приглашаю поиграть в "пятнашки". Помоги мне, попробуй улучшить дизайн. Принципы дизайна, которые надо сохранить — очень простые: если ты посмотришь внимательно на код, то ты обратишь внимание, что модули не знают про структуры данных друг друга — между ними ходят либо абстрактные, либо очень простые типы данных. Предлагается это свойство сохранить, и попытаться уменьшить связность.


Поставив себя сразу в очень удобное от критики положение, тем что я здесь алгоритмами не занимаюсь, а только дизайном, G по сути дела прыгнул с головой в смоляную яму – отличная позиция. Полностью конечно отрешиться от алгоритмов не удалось, появилась какая-то жуткая мистика про живые процессы, которые должны быть мало связанны и не должны что знать друг про друга, а в следующем мастер классе можно будет сказать, что они наоборот теперь жестко связанны и все друг про друга знают. Конечно от геморроя это никак не избавит, а напротив усугубит еще в большей степени чем раньше. Это я могу гарантировать.
Поэтому еще так слаба пояснительная часть написанная псевдокодами, а чего пояснять –то?
Чистописание кода понравилось, я так не умею. Но сам язык беден.
Re[4]: Код expression, sheet, cell: задачка
От: Cyberax Марс  
Дата: 08.11.07 07:27
Оценка: +1
Здравствуйте, sergesokolov, Вы писали:

S>Поэтому еще так слаба пояснительная часть написанная псевдокодами, а чего пояснять –то?

S>Чистописание кода понравилось, я так не умею. Но сам язык беден.
Так ведь все просто: предложи лучшее решение
Sapienti sat!
Re[5]: Код expression, sheet, cell: задачка
От: Трурль  
Дата: 08.11.07 07:46
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Можно обойтись и простым списком значений — без dictionary. Тогда реально все вытягивается в трубу. Ты имеешь в виду вот это?


G>
G>-module( sheet ).

G>evaluate( Ref, Sheet ) ->
G>   Value = get_cell( Ref, Sheet ), % цыклы не ловим, ломает. Понятно, как, но лень
G>   { Context, NewSheet }= mapfoldl( fun evaluate/2, Sheet, cell:dependency_list( Value ) ),
G>   NewValue = cell:evaluate( Value, Context ),
G>   { NewValue, set_cell( Ref, NewValue ) }.
G>...
G>

Да, примерно это.

Но при случае можно разделить анализ зависимостей и собстванно вычисление.
evaluate( Ref, Sheet ) ->
   Value = get_cell( Ref, Sheet ),
   Context = lists:map( fun ( R ) -> get_cell( R, Sheet ) end, cell:dependency_list(Value) ),
   cell:evaluate( Value, Context ).

evaluate( Sheet ) ->
  DepGraph = build_depgraph(Sheet), 
  case digraph_utils:is_acyclic(DepGraph) of
  true ->  
      RefList = digraph_utils:topsort(DepGraph),
      lists:foldl( fun evaluate/2, Sheet, RefList);
  false -> 
      ...
  end.

Не факт, что так будет лучше, но а вдруг?
Re[6]: Код expression, sheet, cell: задачка
От: red75  
Дата: 08.11.07 08:36
Оценка:
Здравствуйте, Трурль, Вы писали:

T>
Т>evaluate( Sheet ) ->
Т>  DepGraph = build_depgraph(Sheet), 
Т>  case digraph_utils:is_acyclic(DepGraph) of
Т>  true ->  
Т>      RefList = digraph_utils:topsort(DepGraph),
Т>      lists:foldl( fun evaluate/2, Sheet, RefList);
Т>  false -> 
Т>      ...
Т>  end.
Т>


Вместо
RefList = digraph_utils:topsort(DepGraph)

наверное лучше
RefList = lists:reverse(digraph_utils:topsort(DepGraph))

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

Кроме того надо будет ввести cell:make_error() для отметки зацикленных ячеек. А циклы удалить, кажется, просто
evaluate(Sheet)->
  ...
  false ->
    CycPart=digraph_utils:reaching(lists:append(digraph_utils:cyclic_strong_components(DepGraph))),
    Sheet1=lists:foldl(fun(Ref,Sheet)->set_cell(Ref,cell:make_error('#cycle'),Sheet) end,Sheet,CycPart),
    digraph:del_vertices(DepGraph,CycPart),
      ...


Хм. Довольно тяжеловесно получается. И вычислительную сложность нужно прикинуть... Вроде-бы O(N)?
Re[9]: Объяснение устройства cell
От: red75  
Дата: 08.11.07 08:37
Оценка:
Здравствуйте, Курилка, Вы писали:

К>А вообще, интересно есть какие-либо исследования/книги посвящённые этой теме? Что-нибудь с обобщённой точки зрения на вопрос, а не конретика по языкам и т.п.?


Да я в общем-то ненастоящий сварщик. Поэтому советовать остерегусь.
Re[5]: Код expression, sheet, cell: задачка
От: sergesokolov Россия http://www.ideashag.spb.ru
Дата: 08.11.07 09:46
Оценка: :)
Здравствуйте, Cyberax, Вы писали:

C>Здравствуйте, sergesokolov, Вы писали:


S>>Поэтому еще так слаба пояснительная часть написанная псевдокодами, а чего пояснять –то?

S>>Чистописание кода понравилось, я так не умею. Но сам язык беден.
C>Так ведь все просто: предложи лучшее решение
решение чего?
мистических вещей, тут одна словестная ловушка в той терминологии которую выдумавает G.
Бьен Страуструп тоже был в определенной степени мистик со скрытием данных, но у него была четкая цель, которой здесь сознательно нет.
Re[6]: Код expression, sheet, cell: задачка
От: Gaperton http://gaperton.livejournal.com
Дата: 08.11.07 10:04
Оценка:
Здравствуйте, Трурль, Вы писали:

Т>Здравствуйте, Gaperton, Вы писали:


G>>Можно обойтись и простым списком значений — без dictionary. Тогда реально все вытягивается в трубу. Ты имеешь в виду вот это?


Т>Да, примерно это.


Т>Но при случае можно разделить анализ зависимостей и собстванно вычисление.

Т>
Т>evaluate( Ref, Sheet ) ->
Т>   Value = get_cell( Ref, Sheet ),
Т>   Context = lists:map( fun ( R ) -> get_cell( R, Sheet ) end, cell:dependency_list(Value) ),
Т>   cell:evaluate( Value, Context ).

Т>evaluate( Sheet ) ->
Т>  DepGraph = build_depgraph(Sheet), 
Т>  case digraph_utils:is_acyclic(DepGraph) of
Т>  true ->  
Т>      RefList = digraph_utils:topsort(DepGraph),
Т>      lists:foldl( fun evaluate/2, Sheet, RefList);
Т>  false -> 
Т>      ...
Т>  end.
Т>

Т>Не факт, что так будет лучше, но а вдруг?

Вряд ли анализ графа оправдан в такой задаче. В чем преимущество? Цыкл — так его поймать можно и попроще. Первый способ — "раскраска" клеток (когда мы берем вычисление значения в "скобки" считаем/несчитаем — как это в моем старом коде сделано и как нормальные люди делают в плюсах), второй способ — передавать "стек" вычислений параметром (это будет set из ref-ов), и проверять, нет ли повторного захода.

"Раскраска" — это одна накладная операция вставки в sheet значения updating при входе в функцию evaluate.
В случае "стека" — две операции вставки и удаления, зато в меньший по размеру set. Я выбрал "раскраску" потому, что дополнительного контейнера таскать а собой не надо. Красивее, штоли. Собственно, код увеличивается на 3 строки.

G>>
G>>-module( sheet ).

G>>evaluate( Ref, Sheet ) ->
G>>   case get_cell( Ref, Sheet ) of
         updating -> { { error, '#cycle' }, Sheet };
         Value ->
             Sheet_1 = set_cell( Ref, updating, Sheet ),
G>>          { Context, NewSheet }= mapfoldl( fun evaluate/2, Sheet_1, cell:dependency_list( Value ) ),
G>>          NewValue = cell:evaluate( Value, Context ),
G>>          { NewValue, set_cell( Ref, NewValue ) }
      end.
G>>...
G>>


Это еще порефакторить можно, чтобы было красиво. Кстати, вот еще одна лажа. Для ошибки надо делать конструктор. А создается она зараза везде. Во всех модулях.

А вообще — все это частности. Твой подход рулит со страшной силой. Так делать (а именно — заставить клетку знать список ячеек, от которых она зависит) — правильно. Именно это решение ключевое — только этот подход позволяет полностью изолировать алгоритм вычисления шыта от вычисления выражений (у меня это было в куче, и меня это беспокоило). И это решение — безусловно решение дизайна, а не алгоритма. Короче, "я всегда жалел, Штирлиц, что вы работаете не в моем департаменте" .
__________________
Кстати, хаскелисты жгут. potan у себя в ЖЖ опубликовал жосткое решение этой задачи на Хаскеле с использованием "релятивистских эффектов". Там клетки с формулами напрямую ленивыми связями на аргументы замыкаются, а потом вычисляются. Жесть.
Re[4]: Код expression, sheet, cell: задачка
От: Gaperton http://gaperton.livejournal.com
Дата: 08.11.07 10:31
Оценка:
Здравствуйте, sergesokolov, Вы писали:

G>>Кстати, приглашаю поиграть в "пятнашки". Помоги мне, попробуй улучшить дизайн. Принципы дизайна, которые надо сохранить — очень простые: если ты посмотришь внимательно на код, то ты обратишь внимание, что модули не знают про структуры данных друг друга — между ними ходят либо абстрактные, либо очень простые типы данных. Предлагается это свойство сохранить, и попытаться уменьшить связность.


S>Поставив себя сразу в очень удобное от критики положение, тем что я здесь алгоритмами не занимаюсь, а только дизайном, G по сути дела прыгнул с головой в смоляную яму – отличная позиция. Полностью конечно отрешиться от алгоритмов не удалось, появилась какая-то жуткая мистика про живые процессы, которые должны быть мало связанны и не должны что знать друг про друга, а в следующем мастер классе можно будет сказать, что они наоборот теперь жестко связанны и все друг про друга знают. Конечно от геморроя это никак не избавит, а напротив усугубит еще в большей степени чем раньше. Это я могу гарантировать.

S>Поэтому еще так слаба пояснительная часть написанная псевдокодами, а чего пояснять –то?
S>Чистописание кода понравилось, я так не умею. Но сам язык беден.

Симметричный ответ: Вы, любезный, поставили себя в очень удобное для критики положение. По сути — вы нырнули с головой просто в яму какую-то с чем-то, не скажу с чем. Сами посудите — чистый код вы писать не умеете, проблем дизайна не понимаете, понятие "связности" для вас мистика. И единственное, что вы можете гарантировать — это геморрой. Прям хоть в резюме включай .

Несимметричный ответ: Короче, в этом топике обсуждается проблема и подходы к дизайну для ФЯ. Не мое чистописание, не бедность языков, не алгоритмы (алгоритмы в этой задаче тривиальны — не о чем тут говорить). На примере простой задачи. По существу вопроса есть что сказать? Считаешь, что само понятие дизайна в контексте ФП — глупость? Да ради бога — раскрой тему, с тобой поговорят. Может быть. А вые..ся и переходить на личности здесь не надо.
Re[6]: Условие задачи Problem K
От: Gaperton http://gaperton.livejournal.com
Дата: 08.11.07 10:48
Оценка:
Здравствуйте, sergesokolov, Вы писали:

C>>Так ведь все просто: предложи лучшее решение

S>решение чего?
S>мистических вещей, тут одна словестная ловушка в той терминологии которую выдумавает G.
S>Бьен Страуструп тоже был в определенной степени мистик со скрытием данных, но у него была четкая цель, которой здесь сознательно нет.

Дурачком прикидываться не надо, ок? Вот реальная тестовая задача, которая применялась при найме в реальную компанию — CQG, ее до тебя уже успешно решили уже сотни людей. Так что не надо делать трагическое выражение лица, вставать в позу, и вещать драматическим голосом, работая на публику. Не оценят, посмеются только. Собственно, уже.

http://thesz.livejournal.com/280784.html

Маленький Эксель
----------------

Необходимо реализовать простую электронную таблицу в виде программы, выполняющейся
из командной строки. Она должна уметь обрабатывать ячейки таблицы как и более
продвинутые аналоги, только с упрощенным синтаксисом выражений. Каждая ячейка
может содержать:
— Ничего
— Неотрицательное целое число
— Текстовые строки, которые начинаются с символа '
— Строки-выражения, которые начинаются с символа '=' и могут содержать
неотрицательные целые числа, ссылки на ячейки и простые арифметические
выражения. Скобки запрещены, у всех операций одинаковый приоритет.
Ссылки на ячейки состоят из одной латинской буквы и следующей за ней
цифры.

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

expression ::= '=' term {operation term}*
term ::= cell_reference | nonnegative_number
cell_reference ::= [A-Za-z][0-9] --
operation ::= '+' | '-' | '*' | '/'
text ::= '\'' {printable_character}

Процесс обработки:
— Все выражения должны быть заменены на вычисленный результат.
— Все вычисления выполняются с помощью целочисленной арифметики со знаком.
— Ячейки с текстом должны быть вычислены как соответствующий текст без
префикса '.
— Операции над строками текста запрещены.
— В случае любой ошибки вычисления формулы, вычисляемая ячейка должна содержать
слово-сообщение об ошибке, начинающееся с символа '#'. Используйте короткие,
ясные сообщения. Не надо предоставлять подробности об ошибках в выводе.

Программа должна использовать только стандартные библиотеки и классы и не должна
вызывать сторонние программы, библиотеки или системные компоненты.


Ввод и вывод
------------

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


Выход должен содержать только ожидаемую информацию, включая сообщения об
ошибках, и никакой другой информации в выводе не должно быть, включая и
welcome text. Выход должен быть отформатирован в соответствии с приведенным
ниже примером.

Пример данных:
3 4
12 =C2 3 'Sample
=A1+B1*C1/5 =A2*B1 =B3-C3 'Spread
'Test =4-3 5 'Sheet

Ожидаемый вывод:
12 -4 3 Sample
4 -16 -4 Spread
Test 1 5 Sheet


Указания по решению
-------------------
Необходимо промышленное качество кода. Более короткое и читаемое решение
предпочтительней. Решение должно содержать тестовые примеры и код, использованные
в процессе создания решения. Не забудьте откомментировать код в ключевых
местах. Код должен быть устойчив к ошибкам.

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

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

Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.