LINUX.ORG.RU
ФорумTalks

Все просто ))

 ,


0

1

Вчера вбросил знакомым одну простую задачку, которая слегка ввела их в ступор. Дай-ка и сюда вброшу.

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

// value can be: a,b,c,d,e,f or g
myLongLongNameOfVariable = getName();
if (myLongLongNameOfVariable == 'a' || myLongLongNameOfVariable == 'b' || myLongLongNameOfVariable == 'c' || myLongLongNameOfVariable == 'd' || myLongLongNameOfVariable == 'e' || myLongLongNameOfVariable == 'f') {
    forAllNonDefault();
    if (myLongLongNameOfVariable == 'a') {
        forA();
    } else if (myLongLongNameOfVariable == 'b') {
        forB();
    } else if (myLongLongNameOfVariable == 'c') {
        forC();
    } else if (myLongLongNameOfVariable == 'd') {
        forD();
    } else if (myLongLongNameOfVariable == 'e') {
        forE();
    } else if (myLongLongNameOfVariable == 'f') {
        forF();
    }
} else {
    // last (here 'g') value context (default)
    forDefault();
}

Ваши предложения?

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

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

можно вместо этого использовать сахар в виде swith (Все просто )) (комментарий) вот этот вот тихий ужас, например). иногда — это тоже отчасти правильное решение, но, в общем случае, плохо расширяемое, нечитабельное и портянистое.

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

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

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

виртуальные функции. а у вас — нечитабельная и нерасширяемая портянка. очень весело будет читать ваш код, когда начнётся юникод, или порядок поменяется. например, если надо будет сделать так:

dispatch 'a' = Just forB
dispatch 'b' = Just forC 
dispatch 'с' = Just forC
dispatch 'd' = Just forD
dispatch 'e' = Just forA
dispatch 'f' = Just forF
dispatch 'ф' = Just forRF
dispatch 'a' = Just forRA
dispatch _   = Nothing
next_time ★★★★★
()
Последнее исправление: next_time (всего исправлений: 1)
Ответ на: комментарий от zinfandel

Нет никакого повторения терминов (повторения dispatch вопрос стиля и решается через case, нет излишних конструкций. Каждое выражение несет конкретный смысл:

Получить имя. Передать в branching. Если имя диспатчится, выполнить forAllNonDefault, а затем функцию к которой придиспатчилось. Иначе, выполнить forDefault.

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

Я не знаком с виртуальными функциями, а примеры в википедии выглядят страшно.

Я уже обновил немного пример и если ожидается, что dispatch разростется, то можно сделать так:

dispatch name = case name of
  'a' -> forA
  'b' -> forB
  'c' -> forC
   .....
  _ - -> fail "no function dispatched"   
zinfandel ★★
()
Ответ на: комментарий от wakuwaku

Да, иногда на чем-нить сидишь пишешь, и тут оп-па, вспоминается сишечка, эхх, щас бы заинлайнить..

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от zinfandel

A eще лучше вот так

dispatch = \case
  'a' -> forA
  'b' -> forB
  'c' -> forC
   .....
  _ - -> fail "no function dispatched"   
zinfandel ★★
()
Ответ на: комментарий от zinfandel
branching myLongNameOfVariable
    | Just f <- dispatch myLongNameOfVariable = forAllNonDefault >> f
    | otherwise = forDefault

Вот это понравилось, всмысле выразительность возможностей ))

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от next_time

если forN() нельзя объединить в функцию с аргументами, то портянку придется расстелить в любом случае, т.к. нужно организовать вызов функции по принципу ключ-значение.

der_looser ★★
()
Ответ на: комментарий от deep-purple

противоречит условию «лаконичным» и «без лапши» — если потребуется 2 одинаковых switch, или разных, но тоже по буквам. тогда свитчи разрастаются ещё в ту портянку...

а виртуальные фу-ции для ровно для решения подобных задач и придумали)

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

В таком случае хз, возможно считать не валидным.

Ну если применить из абстракций к жизни, то, пусть это будет ограниченное число значений в каком-нить конфиге, и на каждое значение уже заготовлены обработчики forN() плюс, если не распознали по значению, тогда тупо дефолт. И да, соответствие имен значение<->обработчик не гарантировано.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от der_looser

Да, царя не хватает, щаз бы разрулил каким-нить супермакросом ))

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от next_time

Ну, а в for_letter() будет содержаться все тот же маппинг между значением и соответствующим действием. Что поменялось?

zinfandel ★★
()
Ответ на: комментарий от deep-purple

ага, именно в таком примере и надо виртуальные функции юзать, обернув в в них forN()

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

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

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

Каким образом этот автомат без свитча узнает какую функцию вызвать при определенном значении если в нем не будет аналога

\case
  'a' -> forA
  'b' -> forB

?

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

Свич будет ближе по «прыжку» ровно как и ифы, в сравнении с дерганьем чего-то лежащим далеко в другом месте. Ну это да, типа экономия на спичках и все такое. Тем не менее.

deep-purple ★★★★★
() автор топика

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

Слишком много параметров нужно минимизировать. Минимизировать можно только один параметр. Условие некорректное.

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

Условие некорректное

Понимаю. Ну можно уточнить для полной абстракции и синтетики:

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

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от Pythagoras

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

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от Pythagoras

Пусть еще немного пообсасывают, если никто аналог не выложит, тогда вброшу портянку ))

deep-purple ★★★★★
() автор топика
if i in "abcdef":
    for_all_non_default()
    try:                         # молимся
        eval("for_" + i + "()")  # стрелаем
    except:                      # скорбим
        pass
else:
    for_default()
der_looser ★★
()
Ответ на: комментарий от Xellos

А оно без лапши и копипасты, да ))

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от zinfandel

Это крутая фича же. Я сразу понял чо оно делает, нативно конечно, но понял.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Свич будет ближе по «прыжку» ровно как и иф

только вот такой инструкции как switch не существует. на самом деле, switch как раз и заменяется на месте виртуальными функциями. что касается if-ов, то 2-3 условных переходов съест больше, чем вызов функции по указателю.

Ну это да, типа экономия на спичках

скорее, как раз, расточительство этих самых спичек

next_time ★★★★★
()
Ответ на: комментарий от deep-purple

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

В том, что я написал, все переменные храним в массиве, а в роли названия выступает индекс, и делаем свитч по этому индексу.

cvs-255 ★★★★★
()
Последнее исправление: cvs-255 (всего исправлений: 1)
Ответ на: комментарий от next_time

А как будут выглядеть объявления всех этих MyLetter. Что-бы был полный рабочий код (как в моих примерах).

Не нравится мне идея заводить отдельный класс, спец функцию getName() под этот класс, и кучу инстасов этого класса просто для того что-бы паттерн-матчить аргумент. Я не понимаю, чем эта буква на основе которой мы решаем что делать отличается от обычной буквы настолько чтобы заслужить отдельного представления/типа/класса ? А если мы пишем какой-нибудь парсер и у нас в одном файле будет под пол-сотни таких ветвлений. На каждое заводить отдельный MyLetter?

zinfandel ★★
()
Последнее исправление: zinfandel (всего исправлений: 1)
Ответ на: комментарий от zinfandel

A еще, я правильно понимаю, что forAllNonDefault() будет копипаститься в каждую реализацию for_letter ?

zinfandel ★★
()
if 'a' <= myLongLongNameOfVariable <= 'g':
    forAllNonDefault()
    forTraTaTa[myLongLongNameOfVariable]()
else:
    forDefault()
MyTrooName ★★★★★
()
Последнее исправление: MyTrooName (всего исправлений: 1)
switch (myLongLongNameOfVariable) {
    case 'a':
    case 'b':
    case 'c':
    case 'd':
    case 'e':
    case 'f':
        forAllNonDefault();
        break;
    default:
        forDefault();
}

switch (myLongLongNameOfVariable) {
    case 'a': forA(); break;
    case 'b': forB(); break;
    case 'c': forC(); break;
    case 'd': forD(); break;
    case 'e': forE(); break;
    case 'f': forF(); break;
}
TheAnonymous ★★★★★
()
Ответ на: комментарий от crowbar
>>> None()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
>>> (lambda: None)()
>>>
Deleted
()
Ответ на: комментарий от next_time

расточительство этих самых спичек

Реализовал на пыхпыхе http://pastebin.com/gLQ7gwjn и на жс http://pastebin.com/vPbZYe1z - свитчи уделали твоих калбяков и там и там. Если есть желание подправить наскоро написанные тесты, я не против.

deep-purple ★★★★★
() автор топика
Последнее исправление: deep-purple (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.