Здравствуйте, AndrewVK, Вы писали:
ВВ>> Двойной проход AVK>Какой такой двойной проход?
Ну предполагается, что получив отобранную таким образом коллекцию, мы с ней что-то сделаем, т.е. совершим проход по ней, так ведь? Первоначальный код делает все в один проход. В твоем варианте я *предполагаю*, что ты просто забыл дописать в конце ToList. Вот тебе и двойной проход. А ToList там, мягко говоря, нужен.
И, кстати, его необходимость как раз и выдает главную проблему этого кода. Автору топика поведение (||) кажется неочевидным. Ты вместо этого заменил все на non-strict последовательность (без мемоизации!), причем с побочным эффектом.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Ну предполагается, что получив отобранную таким образом коллекцию, мы с ней что-то сделаем, т.е. совершим проход по ней, так ведь?
Ну да. Ровно один проход.
ВВ> Первоначальный код делает все в один проход. В твоем варианте я *предполагаю*, что ты просто забыл дописать в конце ToList.
Ну ты крут. Ничего я не забывал, и никаких двойных проходов нет.
ВВ> Вот тебе и двойной проход. А ToList там, мягко говоря, нужен
Зачем? Следующей строкой будет foreach. А если ты собрался результат отдавать наружу, то надо просто вынести каунтер в специальное хранилище, чтобы интерференции не было.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
Здравствуйте, AndrewVK, Вы писали:
ВВ>>Ну предполагается, что получив отобранную таким образом коллекцию, мы с ней что-то сделаем, т.е. совершим проход по ней, так ведь? AVK>Ну да. Ровно один проход. ВВ>> Первоначальный код делает все в один проход. В твоем варианте я *предполагаю*, что ты просто забыл дописать в конце ToList. AVK>Ну ты крут. Ничего я не забывал, и никаких двойных проходов нет.
Нет, я просто пытаюсь представить, как должен выглядеть твой код *на самом деле*. Ведь не совсем так, как ты написал, правда? Теперь вот оказывается, что надо каунтер выносить в некое "специальное хранилище" (это, кстати, что такое?). При этом вообще-то проблемой первоначального варианта называлась неочевидность.
В общем можно полный код в студию. Со специальными хранилищами и всем прочим. У меня вот все же есть определенное подозрение, что твой вариант все же содержит некоторое количество изврата.
Здравствуйте, AndrewVK, Вы писали:
AVK>Нет никакого полного кода. Идею я продемонстрировал, а флудить тебе придется без меня.
Ну ради бога. Мне вот просто показалось немного странным, что в ветке, где все пытаются привести чистое, без побочных эффектов и прочего вселенского зла решение, ты показал отличный способ, каким локальную мутируемую переменную (что само по себе не проблема) неявным образом превратить в нелокальную мутируемую переменную (что уже очень даже проблема). А в конце поставил жирное троеточие.
Я лишь просто поинтересовался у тебя, в чем, собственно, заключалась продемонстрированная идея. А теперь, оказывается, у меня с восприятием проблемы. Ну пусть так
Знаю, что говорю сам с собой, но из любви к искусству ещё вариант с циклом:
def gen(items, myself, limit):
for item in items:
if item.owner != myself:
yield item
elif limit:
limit -= 1
yield item
else:
return
for item in gen(items, myself, limit): processItem(item)
Внешнего счётчика нет, функция (processItem), которая теоретически может дать побочный эффект, не находится в дебрях кода. Поэтому её в тестах легко можно заменить на подделку.
Здравствуйте, Roman Odaisky, Вы писали:
RO>А вот и нет. Проблема осталась: при добавлении условий легко напутать и поставить их не туда, сбив подсчет limit. Ну и ветка else лишняя.
else не лишний — без него цикл пройдёт по всему списку. Проблема с условиями сомнительна: почему её не будет при других подходах?
RO>Интересно подобрать декларативный подход, не императивный.
Здравствуйте, Kogrom, Вы писали:
RO>>А вот и нет. Проблема осталась: при добавлении условий легко напутать и поставить их не туда, сбив подсчет limit. Ну и ветка else лишняя. K>else не лишний — без него цикл пройдёт по всему списку. Проблема с условиями сомнительна: почему её не будет при других подходах?
Так он и должен идти по всему списку. Задача же обработать все элементы, у которых owner != myself (плюс доп. условие). У вас же получается, что как только лимит кончается и попадается первый элемент, у которого owner == myself, то вы выходите из функции. А это неправильно, т.к. в списке могут быть еще элементы, удовлетворяющие первому условию.
RO>>Интересно подобрать декларативный подход, не императивный. K>С этого надо было начинать.
Я так понимаю, идея ТС в том, чтобы максимально упростить добавление новых условий. Здесь декларативный подход напрашивается сам собой — чтобы была возможность эти условия просто комбинировать. Вариант, который я привел, тоже, конечно, не идеален:
open core
let apply f c e | c e is Some c' = f e $ c'
| else = c
let comb p max n e | p e = Some (comb p max n)
| n < max = Some (comb p max (n+1))
| else = None
let process act comb xs = foldl (apply act) comb xs
process processItem (comb even 5 0) [1..100]
Однако в нем по крайней мере можно ввести дополнительный комбинатор и делать так:
let orelse p a e | p e = a e | else = ()
process (processItem |> orelse (<25) |> orelse (>5) ) (comb even 5 0) [1..100]
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Так он и должен идти по всему списку.
Да, действительно. Значит код будет ещё короче. Тогда условия не влияют друг на друга и нет проблемы в добавлении новых (elif limit легко можно поменять на if item.owner == myself and limit).
Но, конечно, если бы я не ошибся в понимании условия задачи, и не требовалось проходить по всему списку, то порядок условий имел бы значение.
Ладно, извините, что я вторгся в клуб любителей ФП со своими циклами и за мою пониженную внимательность.